Minimal (?) protype-based language.
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 

357 righe
7.7 KiB

// 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;
}
}
// Sequence
Sequence = Object.subtype(#Sequence);
Sequence.match(stream, context, actions) {
i = 0;
match = 1;
while (i < self.length() && match == 1) {
match = self[i].match(stream, context, actions);
}
match;
}
// Alternation
Alternation = Object.subtype(#Alternation);
Alternation.match(stream, context, actions) {
i = 0;
match = 0;
while(i < self.length() && match == 0){
initialActionCount = actions.length();
match = self[i].match(stream, context, actions);
if (match == 0) {
while (actions.length() > initialActionCount) {
actions.pop();
}
}
}
}
// 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);