Skip to content

Commit

Permalink
Fixed branching for module _init zone
Browse files Browse the repository at this point in the history
  • Loading branch information
MihailRis committed Jan 19, 2023
1 parent 687c0e8 commit 1908d30
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 63 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- [OiObject](#oiobject)
- [Built-in modules](#built-in-modules):
- [std](#std)
- [API](#api)
## About:
Simple dynamic-typed scripting engine and language with Python-like syntax
for use in Java applications.
Expand Down Expand Up @@ -187,3 +188,11 @@ will be converted to
std._included["$new"](SomeProto, arg1, arg2, arg3)
```

## API
OiScript.eval(expression_string) calculates an expression result.
```java
OiScript.eval("20 - 5 * 3.2") -> 4.0
OiScript.eval("2 * 3 == 6") -> true
OiScript.eval("[]") -> mihailris.oiscript.OiVector extends ArrayList<Object>
OiScript.eval("sqrt(81)") -> 9.0
```
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
<groupId>com.github.MihailRis</groupId>
<artifactId>oiscript</artifactId>
<version>0.91</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<properties>
<maven.compiler.source>8</maven.compiler.source>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/mihailris/oiscript/OiScript.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
public class OiScript {
public static final int VERSION_MAJOR = 0;
public static final int VERSION_MINOR = 9;
public static final int VERSION_PATCH = 2;
public static final int VERSION_PATCH = 3;
public static final String VERSION_STRING = VERSION_MAJOR+"."+VERSION_MINOR+"."+VERSION_PATCH;

public static Script load(String filename, String source, OiObject globals, OiObject scripts) throws ParsingException {
Expand Down
98 changes: 59 additions & 39 deletions src/main/java/mihailris/oiscript/parsing/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,28 @@ private void printTree(ScriptComponent component) {

private void printTree(List<Command> commands, int indent) {
for (Command command : commands) {
System.out.print((command.getPosition().line+1)+"| ");
for (int i = 0; i < indent; i++) {
System.out.print(" ");
printTree(command, indent);
}
}

private void printTree(Command command, int indent) {
System.out.print((command.getPosition().line+1)+"| ");
for (int i = 0; i < indent; i++) {
System.out.print(" ");
}
System.out.println(command);
List<Command> subcommands = command.getCommands();
if (subcommands != null) {
printTree(subcommands, indent + 1);
}
if (command instanceof If) {
If branch = (If) command;
for (Elif elif : branch.getElifs()) {
printTree(elif, indent);
}
System.out.println(command);
List<Command> subcommands = command.getCommands();
if (subcommands != null) {
printTree(subcommands, indent + 1);
Else elseblock = branch.getElseBlock();
if (elseblock != null) {
printTree(elseblock, indent);
}
}
}
Expand Down Expand Up @@ -223,32 +237,10 @@ private List<Command> _requireBlock(int leastIndent, boolean procedure, boolean
continue;
}
throw new ParsingException(source, command.position, "invalid use of elif/else ('if' missing)");
} else {
If ifnode;
if (previous instanceof If) {
ifnode = (If) previous;
} else {
ifnode = ((Elif)previous).getIf();
}
assert (ifnode != null);
if (ifnode.getElseBlock() != null) {
throw new ParsingException(source, position, "'if' is already has 'else' block");
}
if (command instanceof Elif) {
Elif elif = (Elif) command;
elif.setIfNode(ifnode);
ifnode.add(elif);
} else {
Else elseNode = (Else) command;
ifnode.add(elseNode);
}
commands.remove(command);
i--;
}
}
previous = command;
}
//System.out.println(commands);
return commands;
}

Expand Down Expand Up @@ -313,18 +305,34 @@ private Command parseCommand(boolean procedure, boolean loop, int indent) throws
Value value = parseValue(indent);
return new Print(cmdpos, value);
}
case IF:
case ELIF: {
case IF: {
Value condition = parseValue(indent);
List<Command> commands = requireBlock(procedure, true, indent+1);
if (token.equals(ELIF))
return new Elif(cmdpos, condition, commands);
else
return new If(cmdpos, condition, commands);
List<Command> commands = requireBlock(procedure, loop, indent+1);
If branch = new If(cmdpos, condition, commands);
skipEmptyLines();
Position initpos = position.cpy();
while (!isEnd()) {
initpos.set(position);
String keyword = expectToken();
switch (keyword) {
case ELIF:
condition = parseValue(indent);
commands = requireBlock(procedure, loop, indent+1);
branch.add(new Elif(initpos.cpy(), condition, commands));
break;
case ELSE:
commands = requireBlock(procedure, loop, indent+1);
branch.add(new Else(initpos.cpy(), commands));
return branch;
default:
position.set(initpos);
return branch;
}
}
return branch;
}
case ELSE: {
List<Command> commands = requireBlock(procedure, true, indent+1);
return new Else(cmdpos, commands);
throw new ParsingException(source, cmdpos, "'else' out of 'if' context");
}
case FOR: {
if (position.pos < chars.length && chars[position.pos] == ';') {
Expand All @@ -345,7 +353,19 @@ private Command parseCommand(boolean procedure, boolean loop, int indent) throws
case WHILE: {
Value condition = parseValue(indent);
List<Command> commands = requireBlock(procedure, true, indent+1);
return new While(cmdpos, condition, commands);
While whileloop = new While(cmdpos, condition, commands);
Position initpos = position.cpy();
if (!isEnd()) {
initpos.set(position);
String keyword = expectToken();
if (ELSE.equals(keyword)) {
commands = requireBlock(procedure, loop, indent + 1);
whileloop.add(new Else(initpos, commands));
} else {
position.set(initpos);
}
}
return whileloop;
}
case RETURN: {
Value value = null;
Expand Down
33 changes: 33 additions & 0 deletions src/main/test/mihailris/oiscript/OiScriptTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package mihailris.oiscript;

import mihailris.oiscript.exceptions.ParsingException;
import org.junit.Test;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class OiScriptTest {
@Test
public void evalTest() throws ParsingException {
assertEquals(OiScript.eval("20 - 5 * 3.2"), 4.0);
assertEquals(OiScript.eval("2 * 3 == 6"), true);
assertTrue(OiScript.eval("[]") instanceof List);
assertEquals(OiScript.eval("sqrt(81)"), 9.0);
}

@Test
public void scriptTest() throws ParsingException {
String sourceCode =
"a = 5\n" +
"b = 12\n" +
"if a > b:\n" +
" print(a)\n" +
"else:\n" +
" print(b)\n";
OiObject globals = new OiObject();
OiObject scripts = new OiObject();
Script script = OiScript.load("test.oi", sourceCode, globals, scripts);
}
}
28 changes: 6 additions & 22 deletions test.oi
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
func tostr(self):
return "User(name: "+cat(self.name)+", age: "+self.age+")"
a = 5
b = 10

func User_init(self, name, age):
self.name = name
self.age = age

# define prototype User
User = {"_init": User_init, "_str": tostr}

# define object that use User as prototype
# using default $new(...) implementation
print(new User("unknown", 45)._str())

func custom_new(prototype, *args):
obj = {"_proto": prototype}
obj._init(*args)
print("CUSTOM NEW USED with prototype", prototype, "args:", args)
return obj
script._included["$new"] = custom_new

# using user-defined $new(...) implementation
print(new User("Tester", 90)._str())
if a > b:
print(a)
else:
print(b)
27 changes: 26 additions & 1 deletion tests.oi
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,29 @@ func quadratic_equation(a, b, c):
x2 = (-b + rd)/(2*a)
return [x1, x2]

print(quadratic_equation(1, 2, -3))
print(quadratic_equation(1, 2, -3))


func tostr(self):
return "User(name: "+cat(self.name)+", age: "+self.age+")"

func User_init(self, name, age):
self.name = name
self.age = age

# define prototype User
User = {"_init": User_init, "_str": tostr}

# define object that use User as prototype
# using default $new(...) implementation
print(new User("unknown", 45)._str())

func custom_new(prototype, *args):
obj = {"_proto": prototype}
obj._init(*args)
print("CUSTOM NEW USED with prototype", prototype, "args:", args)
return obj
script._included["$new"] = custom_new

# using user-defined $new(...) implementation
print(new User("Tester", 90)._str())

0 comments on commit 1908d30

Please sign in to comment.