|
|
@ -0,0 +1,326 @@ |
|
|
|
// Utils |
|
|
|
|
|
|
|
println = (x) { |
|
|
|
if (!x) { |
|
|
|
print("\n"); |
|
|
|
} else { |
|
|
|
print(x, "\n", full: 1); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Object.subtype(name) { self.new(__name__: name) } |
|
|
|
|
|
|
|
// Input stream |
|
|
|
|
|
|
|
Stream = Object.subtype(#Stream); |
|
|
|
|
|
|
|
newStream(string) { |
|
|
|
self = Stream.new( |
|
|
|
content: string, |
|
|
|
position: 0, |
|
|
|
limit: len(string) |
|
|
|
); |
|
|
|
print("Created new stream object: { position: ", self.position, ", limit: ", self.limit, ", !atEnd(): ", !self.atEnd(), " }\n"); |
|
|
|
self; |
|
|
|
} |
|
|
|
|
|
|
|
Stream.atEnd() { self.position >= self.limit } |
|
|
|
Stream.peek() { !self.atEnd() && self.content[self.position] } |
|
|
|
Stream.inc() { !self.atEnd() && { self.position = self.position + 1; } } |
|
|
|
|
|
|
|
Stream.next() { |
|
|
|
!self.atEnd() && { |
|
|
|
c = self.content[self.position]; |
|
|
|
self.position = self.position + 1; |
|
|
|
c; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Stream.setLastBegin = () { self.lastBegin = self.position; }; |
|
|
|
|
|
|
|
// Context |
|
|
|
|
|
|
|
Context = Object.subtype(#Context); |
|
|
|
Context.init() { self.variables = []; self; } |
|
|
|
Context.declareVariable(var) { self.variables[var] = nil } |
|
|
|
|
|
|
|
// String Literal |
|
|
|
|
|
|
|
StringLiteral = Object.subtype(#StringLiteral); |
|
|
|
|
|
|
|
StringLiteral.match(stream, context, actions) { |
|
|
|
|
|
|
|
n = len(self.string); |
|
|
|
i = 0; |
|
|
|
success = 1; |
|
|
|
startCursor = stream.cursor; |
|
|
|
|
|
|
|
while(i < n && success == 1) { |
|
|
|
if (self.string[i] != stream.peek()) { |
|
|
|
success = 0; |
|
|
|
stream.cursor = startCursor; |
|
|
|
|
|
|
|
} else { |
|
|
|
i = i + 1; |
|
|
|
stream.inc(); |
|
|
|
} |
|
|
|
} |
|
|
|
success; |
|
|
|
} |
|
|
|
|
|
|
|
// Character Class |
|
|
|
|
|
|
|
CharacterClass = Object.subtype(#CharacterClass); |
|
|
|
|
|
|
|
CharacterClass.match(stream, context, actions) { |
|
|
|
|
|
|
|
classLength = len(self.value); |
|
|
|
i = 0; |
|
|
|
prevChar = nil; |
|
|
|
success = 0; |
|
|
|
|
|
|
|
while (i < classLength && success == 0) { |
|
|
|
|
|
|
|
// [a] case |
|
|
|
if (prevChar == nil) { |
|
|
|
// println("[a] case"); |
|
|
|
prevChar = self.value[i]; |
|
|
|
|
|
|
|
if (stream.peek() == self.value[i]) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
|
|
|
|
} else if (prevChar != nil && self.value[i] == ord('-')) { |
|
|
|
|
|
|
|
// [a-z] case |
|
|
|
if (i+1 < classLength) { |
|
|
|
// println("[a-z] case"); |
|
|
|
rangeStart = charValue(prevChar); |
|
|
|
rangeEnd = charValue(self.value[i+1]); |
|
|
|
// print("Range Start: ", rangeStart, " | "); |
|
|
|
// print("Range End: ", rangeEnd, "\n"); |
|
|
|
if (charValue(stream.peek()) >= rangeStart |
|
|
|
&& charValue(stream.peek()) <= rangeEnd |
|
|
|
) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
prevChar = nil; |
|
|
|
i = i + 1; |
|
|
|
|
|
|
|
// [a-] case |
|
|
|
} else { |
|
|
|
// println("[a-] case"); |
|
|
|
if (stream.peek() == ord('-')) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// [ab] case |
|
|
|
} else if (prevChar != nil && self.value[i] != ord('-')) { |
|
|
|
// println("[ab] case"); |
|
|
|
prevChar = self.value[i]; |
|
|
|
if (stream.peek() == self.value[i]) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
// print("prevChar: ", prevChar, "\n"); |
|
|
|
i = i + 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (success == 1) { |
|
|
|
stream.inc(); |
|
|
|
} |
|
|
|
|
|
|
|
success; |
|
|
|
} |
|
|
|
|
|
|
|
// Dot |
|
|
|
|
|
|
|
Dot = Object.subtype(#Dot); |
|
|
|
|
|
|
|
Dot.match(stream, context, actions) { |
|
|
|
if (stream.peek() != nil) { |
|
|
|
stream.inc(); |
|
|
|
1; |
|
|
|
} else { |
|
|
|
0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Begin |
|
|
|
|
|
|
|
Begin = Object.subtype(#Begin); |
|
|
|
|
|
|
|
Begin.match(stream, context, actions) { |
|
|
|
stream.setLastBegin(); |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// End |
|
|
|
|
|
|
|
End = Object.subtype(#End); |
|
|
|
|
|
|
|
End.match(stream, context, actions) { |
|
|
|
context.input = stream.string[stream.lastBegin..stream.cursor]; |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// Optional (? postfix operator) |
|
|
|
|
|
|
|
Optional = Object.subtype(#Optional); |
|
|
|
|
|
|
|
Optional.match(stream, context) { |
|
|
|
self.innerExpression.match(stream, context); |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// Star |
|
|
|
|
|
|
|
Star = Object.subtype(#Star); |
|
|
|
|
|
|
|
Star.match(stream, context, actions) { |
|
|
|
while (self.innerExpression.match(stream, context) == 1) {} |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// Plus |
|
|
|
|
|
|
|
Plus = Object.subtype(#Plus); |
|
|
|
|
|
|
|
Plus.match(stream, context, actions) { |
|
|
|
if (self.innerExpression.match(stream, context) == 1) { |
|
|
|
while (self.innerExpression.match(stream, context) == 1) {} |
|
|
|
1; |
|
|
|
} else { |
|
|
|
0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// And |
|
|
|
|
|
|
|
And = Object.subtype(#And); |
|
|
|
|
|
|
|
And.match(stream, context, actions) { |
|
|
|
position = stream.position; |
|
|
|
|
|
|
|
if (self.innerExpression.match(stream, context) == 1) { |
|
|
|
stream.position = position; |
|
|
|
1; |
|
|
|
} else { |
|
|
|
0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Not |
|
|
|
|
|
|
|
Not = Object.subtype(#Not); |
|
|
|
|
|
|
|
Not.match(stream, context, actions) { |
|
|
|
position = stream.position; |
|
|
|
|
|
|
|
if (self.innerExpression.match(stream, context) == 1) { |
|
|
|
stream.position = position; |
|
|
|
0; |
|
|
|
} else { |
|
|
|
1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Action |
|
|
|
|
|
|
|
Action = Object.subtype(#Action); |
|
|
|
|
|
|
|
Action.match(stream, context, actions) { |
|
|
|
actions.push(self); |
|
|
|
self.context = context; |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
Action.execute() { |
|
|
|
|
|
|
|
// Declare all variables that a value is set to in the context |
|
|
|
for (statement in self.parseTree.body) { |
|
|
|
if (statement.__name__ == "SetVar") { |
|
|
|
self.context.declareVariable(statement.name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Evaluate the parse tree and return to outer context if needed |
|
|
|
returnValue = eval(self.parseTree, env: self.context.variables); |
|
|
|
if (self.context.outerContext != nil) { |
|
|
|
self.context.outerContext.variables[self.context.returnValueName] = returnValue; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Assignment |
|
|
|
|
|
|
|
Assignment = Object.subtype(#Assignment); |
|
|
|
|
|
|
|
Assignment.match(stream, context, actions) { |
|
|
|
context.declareVariable(self.variableName); |
|
|
|
innerContext = Context.new(outerContext: context, returnValueName: self.variableName).init(); |
|
|
|
self.rule.match(stream, innerContext, actions); |
|
|
|
} |
|
|
|
|
|
|
|
// Main |
|
|
|
|
|
|
|
// stream = newStream(readfile("input.txt")); |
|
|
|
stream = newStream("asdf1234"); |
|
|
|
context = Context.new(outerContext: nil).init(); |
|
|
|
actions = []; |
|
|
|
|
|
|
|
// s = StringLiteral.new(string: "ab"); |
|
|
|
// print("Success : ", s.match(stream), "\n"); |
|
|
|
|
|
|
|
// c = CharacterClass.new(value: " \n\t"); |
|
|
|
// print("Parsing Character: ", stream.peek(), " | CharacterClass [", c.value,"] : ", c.match(stream), "\n"); |
|
|
|
|
|
|
|
// d = Dot.new(); |
|
|
|
// print("Parsing Character: ", stream.peek(), " | Dot : ", d.match(stream, context), "\n"); |
|
|
|
|
|
|
|
println("\n--- Action Test ---\n"); |
|
|
|
|
|
|
|
actionParseTree = `{ |
|
|
|
innerVar = 151; |
|
|
|
}; |
|
|
|
|
|
|
|
act = Action.new(parseTree: actionParseTree); |
|
|
|
|
|
|
|
assign = Assignment.new(variableName: #outerVar, rule: act); |
|
|
|
assign.match(stream, context, actions); |
|
|
|
|
|
|
|
actionParseTree2 = `{ |
|
|
|
x = 69; |
|
|
|
}; |
|
|
|
|
|
|
|
act2 = Action.new(parseTree: actionParseTree2); |
|
|
|
act2.match(stream, context, actions); |
|
|
|
|
|
|
|
for (action in actions) { |
|
|
|
action.execute(); |
|
|
|
} |
|
|
|
|
|
|
|
print("global variable named innerVar => ", innerVar, " should be nil\n"); |
|
|
|
print("global variable named x => ", x, " should be nil\n"); |
|
|
|
|
|
|
|
print(context, "\n", full: 1); |
|
|
|
|
|
|
|
// c = CharacterClass.new(value: "a"); |
|
|
|
// u = Not.new(innerExpression: c); |
|
|
|
// println(u.match(stream, context)); |
|
|
|
// println(stream); |
|
|
|
// |
|
|
|
// println(); |
|
|
|
// println(); |
|
|
|
// println(); |
|
|
|
// |
|
|
|
// gensokyo = [buses: 0, inhabitants: 1337]; |
|
|
|
// |
|
|
|
// reimu = [location: gensokyo]; |
|
|
|
// marisa = [location: gensokyo]; |
|
|
|
// |
|
|
|
// println(marisa.location); |
|
|
|
// reimu.location.inhabitants = 42; |
|
|
|
// println(marisa.location); |
|
|
|
|