Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
448 lines (419 sloc) 9.9 KB
import "ast.pil"
import gel
import gel::util
class gel::ParseException extends Exception {
new(String message) extends super(message) {
}
}
Term gel::util::valueOrEmpty(Term t) {
if(t == null) {
return new EmptyTerm();
} else {
return t;
}
}
class gel::Parser {
String text = "";
Int i = 0;
Int keywordLevel = 9;
Int followLevel = 0;
Array<Array<String>> operators = new Array<Array<String>>(
new Array<String>(".", "_"),
new Array<String>("*", "/", "%"),
new Array<String>("+", "-"),
new Array<String>("<", "<=", ">", ">="),
new Array<String>("!", "=", "+=", "-=", "*=", ":=", "!="),
new Array<String>("&"),
new Array<String>("|"),
new Array<String>("?", ":", "$"),
new Array<String>(","),
new Array<String>("keyword"),
new Array<String>(";")
);
List<String> noWhitespaceOps = new List<String>(";", ",", ".", "_");
List<Char> allOps = new List<Char>('!', '@', '#', '%', '^', '&', '*', '-', '+', '=', '|', '/', '\\', '<', '>', '.', '?');
Array<String> prefixOps = new Array<String>("+", "-", "*", "<", ">", "?", "!", ":", "`", "$");
new(String text) {
this.text = text;
}
Term followFactor(Term t) {
var oldI = i;
if(!acceptWhiteSpace()) { // Postfix
var op = acceptOps(prefixOps);
if(op != null) {
t = new OpTerm(op, t, null);
}
acceptWhiteSpace();
oldI = i;
}
//var exp = acceptExp();
var exp = acceptGeneric(followLevel);
if(exp == null) {
i = oldI;
return t;
}
while(exp != null) {
oldI = i;
acceptWhiteSpace();
t = new OpTerm("_", t, exp);
//exp = acceptExp();
exp = acceptGeneric(followLevel);
if(exp == null) {
i = oldI;
return t;
}
}
return t;
}
/*
Term acceptFactor() {
var t = acceptFactorNoFollow();
if(t == null) {
return null;
} else {
return followFactor(t);
}
}
*/
Term acceptFactor() { //NoFollow() {
var in = acceptInt();
if(in != -1) {
return new IntTerm(in);
}
var idn = acceptIdn();
if(idn != null && !lookAhead(":")) {
return new SymbolTerm(idn);
} else if(idn != null && lookAhead(":")) {
i = i - idn.length;
}
var s = acceptString();
if(s != null) {
return new StringTerm(s);
}
/*
var mv = acceptMatchVar();
if(mv != null) {
return new MatchVarTerm(mv);
}
*/
var pe = acceptPrefixExp();
if(pe != null) {
return pe;
}
if(accept('(')) {
acceptWhiteSpace();
var exp = acceptExp();
acceptWhiteSpace();
expect(')');
return new GroupTerm('(', valueOrEmpty(exp));
}
if(accept('[')) {
acceptWhiteSpace();
var exp = acceptExp();
acceptWhiteSpace();
expect(']');
return new GroupTerm('[', valueOrEmpty(exp));
}
if(accept('{')) {
acceptWhiteSpace();
var exp = acceptExp();
acceptWhiteSpace();
expect('}');
return new GroupTerm('{', valueOrEmpty(exp));
}
return null;
}
Term acceptPrefixExp() {
var op = acceptOps(prefixOps);
if(op == null) {
return null;
}
var t = acceptFactor(); //acceptGeneric(0);
if(t != null) {
return new OpTerm(op, null, t);
} else {
return null;
}
}
Term acceptGenericKeyword() {
var oldI = i;
acceptWhiteSpace();
var kw = acceptKeyword();
if(kw == null) {
i = oldI;
return acceptGeneric(keywordLevel - 1);
}
acceptWhiteSpace();
var t = acceptGeneric(keywordLevel - 1);
if(t != null) {
//return followFactor(new ConsTerm(1, kw, new Array<Term>(t)));
return new OpTerm(kw, null, t);
} else {
i = oldI;
return null;
}
}
Term acceptGeneric(Int level) {
Term f = null;
if(level == 0) {
f = acceptFactor();
} else if(level == keywordLevel) {
f = acceptGenericKeyword();
//return acceptGenericKeyword();
/*
if(f == null) {
f = acceptGeneric(level-1);
}
*/
} else {
f = acceptGeneric(level-1);
}
if(f == null) {
return null;
}
var t = f;
var oldI = i;
var didAcceptWhitespace = acceptWhiteSpace();
var op = acceptOps(operators[level]);
if(!didAcceptWhitespace && op != null && !noWhitespaceOps.contains(op)) {
//if(level == 0) { // Postfix
t = new OpTerm(op, t, null);
acceptWhiteSpace();
oldI = i;
op = acceptOps(operators[level]);
//} else {
//i = oldI;
//return t;
//}
//if(level == followLevel) {
//return followFactor(t);
//} else {
//}
}
while(op != null) {
if(!acceptWhiteSpace() && !noWhitespaceOps.contains(op)) {
/*
i = oldI;
return t;
*/
t = new OpTerm(op, t, null);
acceptWhiteSpace();
op = acceptOps(operators[level]);
}
Term t2 = null;
if(level == 0) {
t2 = acceptFactor(); // One level lower to ennforce left-recursive parsing
} else {
t2 = acceptGeneric(level);
}
if(t2 == null && op == "_") {
i = oldI;
return t;
}
//t2 = acceptGeneric(level);
t = new OpTerm(op, t, valueOrEmpty(t2));
oldI = i;
if(!acceptWhiteSpace() && !noWhitespaceOps.contains(op)) {
i = oldI;
return t;
}
op = acceptOps(operators[level]);
}
i = oldI;
//if(level == followLevel) {
//return followFactor(t);
//} else {
return t;
//}
}
Term acceptExp() {
acceptWhiteSpace();
return acceptGeneric(operators.length-1);
}
Bool acceptWhiteSpace() {
var oldI = i;
while(i < text.length && (text[i] == ' ' || text[i] == '\t' || text[i] == '\n' || text[i] == '\r' || lookAhead("//") || lookAhead("/*"))) {
if(lookAhead("//")) {
while(i < text.length && text[i] != '\n' && text[i] != '\r') {
i++;
}
} else if(lookAhead("/*")) {
while(i < text.length && !lookAhead("*/")) {
i++;
}
if(lookAhead("*/")) {
i = i + 2;
}
} else {
i++;
}
}
return oldI != i;
}
void printRest() {
var m = new MutableString();
for(Int j = i; j < text.length; j++) {
m.append(text[j]);
}
print("Rest: |");
println(m.as<String>);
}
Bool lookAhead(String str) {
var parsedSomething = false;
for(Int j = 0; j < str.length && i+j < text.length; j++) {
if(text[j+i] != str[j]) {
return false;
}
if(i+j+1 == text.length && j+1 < str.length) {
return false;
}
parsedSomething = true;
}
return parsedSomething;
}
String acceptOps(Array<String> ops) {
var canBeWhiteSpace = false;
for(String op : ops) {
if(op == "_") {
canBeWhiteSpace = true;
} else if(lookAhead(op)) {
var opstr = new MutableString(op);
var oldI = i;
i = i + op.length;
while(i < text.length && allOps.contains(text[i])) {
opstr.append(text[i]);
i++;
}
if(text[i-1] != '=' || opstr.as<String> == op) {
return opstr.as<String>;
} else {
i = oldI;
}
}
}
if(canBeWhiteSpace) {
return "_";
} else {
return null;
}
}
String acceptKeyword() {
var oldI = i;
var idn = acceptIdn();
if(idn == null) {
return null;
}
if(accept(':')) {
return idn + ":";
} else {
i = oldI;
return null;
}
}
Int acceptInt() {
if(i == text.length) {
return -1;
}
var s = new MutableString();
if(text[i] >= '0' && text[i] <= '9') {
while(i < text.length && text[i] >= '0' && text[i] <= '9') {
s.append(text[i]);
i++;
}
return s.as<Int>;
} else {
return -1;
}
}
String acceptString() {
if(i == text.length) {
return null;
}
var s = new MutableString();
if(text[i] == '"') {
i++;
while(i < text.length && text[i] != '"' && text[i-1] != '\\') {
if(!(text[i] == '\\' && i < (text.length + 1) && text[i+1] == '"')) {
s.append(text[i]);
}
i = i + 1;
}
i = i + 1;
return s.as<String>;
} else {
return null;
}
}
Bool accept(Char c) {
if(i == text.length) {
return false;
}
if(text[i] == c) {
i++;
return true;
} else {
return false;
}
}
void expect(Char c) {
if(i == text.length) {
print("Rest of the buffer: ");
printRest();
throw new ParseException("Expected: " + c.as<String>);
}
if(text[i] == c) {
i++;
} else {
print("Rest of the buffer: ");
printRest();
throw new ParseException("Expected: " + c.as<String>);
}
}
String acceptMatchVar() {
if(i == text.length) {
return null;
}
var oldI = i;
if(!accept('@')) {
return null;
}
var idn = acceptIdn();
if(idn == null) {
i = oldI;
return null;
}
if(!accept('@')) {
i = oldI;
return null;
}
return idn;
}
String acceptIdn() {
if(i == text.length) {
return null;
}
var oldI = i;
var sym = new MutableString();
if((text[i] >= 'a' && text[i] <= 'z') ||
(text[i] >= 'A' && text[i] <= 'Z') ||
(text[i] == '_')) {
sym.append(text[i]);
i++;
} else {
return null;
}
// Read constructor
while(i < text.length && ((text[i] >= 'a' && text[i] <= 'z') ||
(text[i] >= 'A' && text[i] <= 'Z') ||
(text[i] >= '0' && text[i] <= '9') ||
(text[i] == '_') || (text[i] == '-'))) {
sym.append(text[i]);
i++;
}
while(i > 1 && text[i-1] == '-') {
i--;
sym.remove(sym.length-1);
}
return sym.as<String>;
}
}