Warning: session_start(): open(/var/lib/php/sessions/sess_auu4kaissg63nl8v2ss3dujgqt, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
/* e.g.
overlay <- ScreenOverlay
bounds <- rightScreenBounds
overlay bounds bounds
overlay show
Can separate commands with ";" also.
For how to define functions in a script see #1033988.
Note: LeftArrowScriptAutoCompleter uses a lot of this class's internals
*/
sclass GazelleV_LeftArrowScriptParser > SimpleLeftToRightParser {
replace Toolbox with GazelleV_LeftArrowScript.
delegate Script to Toolbox.
delegate Evaluable to Toolbox.
replace const with _const.
settable new G22Utils g22utils;
L functionContainers;
new LinkedHashSet knownVars;
Map functionDefs = new Map;
// object can be a class
srecord MethodOnObject(O object, S method) {}
Script parse(S text) {
setText(text);
ret parseScript();
}
Script parseScript() {
new Script script;
script.functionDefs = functionDefs;
try {
parseScript_2(script);
ret script;
} catch e {
print("Parsed so far:\n" + script);
throw rethrowAndAppendToMessage(e, squareBracketed(str(lineAndColumn())));
}
}
void parseScript_2(Script script) {
while (mainLoop()) {
if (is(";")) continue with next();
if (is("}")) break;
S t = token();
print("First token of command: " + t);
if (is("def"))
continue with parseFunctionDefinition();
if (is("while"))
continue with script.add(parseWhileLoop());
if (is("for"))
continue with script.add(parseForEach());
if (is("if"))
continue with script.add(parseIfStatement());
// return is just ignored for now
if (is("return"))
t = tpp();
print("next tokens: " + quote(token(1)) + " " + quote(token(2)));
if (isIdentifier(t) && eq(token(1), "<") && eq(token(2), "-")) {
print("Found assignment");
next(3);
knownVars.add(t);
script.add(new Toolbox.Assignment(t, parseExpr()));
} else
addUnlessNull(script, parseExpr());
}
}
Evaluable parseOptionalInnerExpression() {
printVars parseOptionalInnerExpression(+token());
if (atCmdEnd() || is("{")) null;
ret parseInnerExpr();
}
Evaluable const(O o) { ret new Toolbox.Const(o); }
Evaluable parseInnerExpr() { ret parseExpr(true); }
Evaluable parseExpr(bool inner default false) {
if (atEnd()) null;
S t = token();
printVars parseExpr(token := t);
if (is(";")) null;
// int or double literal
if (is("-") && empty(nextSpace()) && startsWithDigit(token(1))
|| startsWithDigit(t)) {
t = consumeUntilSpaceOrCmdEnd();
ret isInteger(t) ? const(parseInt(t)) : const(parseDouble(t));
}
if (isQuoted(t)) {
consume();
ret const(unquote(t));
}
if (isIdentifier(t)) {
consume();
print("Consumed identifier " + t + ", next token: " + token() + ", inner: " + inner);
ret parseExprStartingWithIdentifier(t, inner);
}
fail("Identifier expected");
}
// t is last consumed token (the identifier the expression starts with)
Evaluable parseExprStartingWithIdentifier(S t, bool inner) {
if (eq(t, "true")) ret const(true);
if (eq(t, "false")) ret const(false);
if (eq(t, "null")) ret const(null);
if (eq(t, "new")) {
S className = assertIdentifier(tpp());
O o = findExternalObject(className);
if (o cast Class)
ret new Toolbox.NewObject(o, parseArguments());
fail("Class not found: " + className);
}
if (knownVars.contains(t)) {
var e = new Toolbox.GetVar(t);
print("Found var acccess: " + e + ", " + (!inner ? "Checking for call" : "Returning expression"));
ret inner ? e : parseCall(e);
}
if (!inner) {
var fdef = functionDefs.get(t);
if (fdef != null)
ret new Toolbox.CallFunction(fdef, parseArguments());
}
O o = findExternalObject(t);
if (o == null)
fail("Unknown object: " + t);
else if (inner)
ret const(o);
else if (o cast Class) {
/*if (atCmdEnd())
ret new Toolbox.NewObject(o);*/
/* old object creation syntax (e.g. Pair new a b)
if (is("new")) {
next();
ret new Toolbox.NewObject(o, parseArguments());
} else*/ if (isIdentifier()) {
S name = tpp();
// look for method first
if (hasMethodNamed(o, name))
ret new Toolbox.CallMethod(const(o), name, parseArguments());
// look for field second
var field = getField(o, name);
if (field != null) {
assertCmdEnd();
ret new Toolbox.GetStaticField(field);
}
fail(name + " not found in " + o + " (looked for method or field)");
} else
fail("Method name expected: " + token());
} else if (o cast MethodOnObject) {
if (inner) fail("Can't call methods in arguments");
ret new Toolbox.CallMethod(const(o.object), o.method, parseArguments());
} else
ret parseCall(const(o));
}
L parseArguments() {
//ret collectWhileNotNull(-> parseOptionalInnerExpression());
new L l;
try {
while (true) {
Evaluable a = parseOptionalInnerExpression();
if (a == null) break;
l.add(a);
}
ret l;
} on fail {
print("Arguments parsed so far: " + l);
}
}
S consumeUntilSpaceOrCmdEnd() {
ret consumeUntilSpaceOr(-> atCmdEnd());
}
bool atCmdEnd() { ret atEndOrLineBreak() || is(";") || is("}"); }
void assertCmdEnd() { if (!atCmdEnd()) fail("Expected end of command"); }
Evaluable parseCall(Evaluable target) {
if (atCmdEnd() || !isIdentifier()) ret target;
var start = ptr();
S methodName = tpp();
var args = parseArguments();
if (nempty(args))
ret new Toolbox.CallMethod(target, methodName, args);
else
ret src(start, new Toolbox.CallMethodOrGetField(target, methodName));
}
A src(TokPtr start, A a) {
if (a cast IHasTokenRangeWithSrc)
a.setTokenRangeWithSrc(TokenRangeWithSrc(start, ptr()));
ret a;
}
// can return MethodOnObject
swappable O findExternalObject(S name) ctex {
//try object findClassThroughDefaultClassFinder(name);
//try object findClassInStandardImports(name);
S fullName = globalClassNames().get(name);
if (fullName != null)
ret Class.forName(fullName);
fOr (container : functionContainers)
if (hasMethodNamed(container, name))
ret new MethodOnObject(container, name);
null;
}
selfType allowTheWorld() { ret allowTheWorld(mc()); }
selfType allowTheWorld(O... functionContainers) {
this.functionContainers = asList(functionContainers);
globalClassNames_cache = null; // recalculate
this;
}
void printFunctionDefs {
print(values(functionDefs));
}
void parseFunctionDefinition() {
consume("def");
S functionName = assertIdentifier(tpp());
new LS args;
while (isIdentifier())
args.add(tpp());
temp tempAddAll(knownVars, args);
var functionBody = parseCurlyBlock();
functionDefs.put(functionName, new Toolbox.FunctionDef(functionName, args, functionBody));
}
Evaluable parseCurlyBlock() {
//print(+knownVars);
consume("{");
var script = parseScript();
consume("}");
ret script;
}
Evaluable parseWhileLoop() {
consume("while");
var condition = parseExpr();
var body = parseCurlyBlock();
ret new Toolbox.While(condition, body);
}
Evaluable parseForEach() {
consume("for");
S var = assertIdentifier(tpp());
print("for var", var);
consume("in");
var collection = parseExpr();
print(+collection);
temp tempAdd(knownVars, var);
var body = parseCurlyBlock();
ret new Toolbox.ForEach(collection, var, body);
}
Evaluable parseIfStatement() {
consume("if");
var condition = parseExpr();
var body = parseCurlyBlock();
ret new Toolbox.IfThen(condition, body);
}
// declare an external variable
void addVar(S var) { knownVars.add(var); }
// short name to full name
simplyCached SS globalClassNames() {
var packages = mapToTreeSet(importedPackages(), pkg -> pkg + ".");
// add inner classes of function containers
var classContainers = classContainerPrefixes();
new SS out;
for (className : g22utils.classNameResolver().allFullyQualifiedClassNames()) {
if (!contains(className, '$')) {
S pkg = longestPrefixInTreeSet(className, packages);
if (pkg != null) {
S shortName = dropPrefix(pkg, className);
if (!shortName.contains("."))
out.put(shortName, className);
}
}
S container = longestPrefixInTreeSet(className, classContainers);
if (container != null)
out.put(dropPrefix(container, className), className);
}
ret out;
}
swappable Cl importedPackages() {
ret itemPlus("java.lang", standardImports_fullyImportedPackages());
}
TreeSet classContainerPrefixes() {
ret mapToTreeSet(functionContainers, fc -> className(fc) + "$");
}
}