mirror of https://github.com/adamdruppe/arsd.git
more stuff
This commit is contained in:
parent
31eb1590cf
commit
847f12f2e5
70
jsvar.d
70
jsvar.d
|
@ -48,21 +48,17 @@ import std.json;
|
||||||
it should consistently throw on missing semicolons
|
it should consistently throw on missing semicolons
|
||||||
|
|
||||||
*) nesting comments, `` string literals
|
*) nesting comments, `` string literals
|
||||||
|
*) opDispatch overloading
|
||||||
*) properties???//
|
*) properties???//
|
||||||
a.prop on the rhs => a.prop()
|
a.prop on the rhs => a.prop()
|
||||||
a.prop on the lhs => a.prop(rhs);
|
a.prop on the lhs => a.prop(rhs);
|
||||||
if opAssign, it can just do a.prop(a.prop().opBinary!op(rhs));
|
if opAssign, it can just do a.prop(a.prop().opBinary!op(rhs));
|
||||||
|
|
||||||
But, how do we mark properties in var? Can we make them work this way in D too?
|
But, how do we mark properties in var? Can we make them work this way in D too?
|
||||||
0) add global functions to the object like assert()
|
0) add global functions to the object (or at least provide a convenience function to make a pre-populated global object)
|
||||||
1) ensure operator precedence is sane
|
1) ensure operator precedence is sane
|
||||||
2) a++ would prolly be nice, and def -a
|
2) a++ would prolly be nice, and def -a
|
||||||
3) loops (foreach - preferably about as well as D (int ranges, arrays, objects with opApply overloaded, and input ranges), do while?)
|
|
||||||
foreach(i; 1 .. 10) -> for(var i = 1; i < 10; i++)
|
|
||||||
foreach(i; array) -> for(var i = 0; i < array.length; i++)
|
|
||||||
foreach(i; object) -> for(var v = new object.iterator; !v.empty(); v.popFront()) { var i = v.front(); / *...* / }
|
|
||||||
4) switches?
|
4) switches?
|
||||||
6) explicit type conversions somehow (cast?)
|
|
||||||
10) __FILE__ and __LINE__ as default function arguments should work like in D
|
10) __FILE__ and __LINE__ as default function arguments should work like in D
|
||||||
16) stack traces on script exceptions
|
16) stack traces on script exceptions
|
||||||
17) an exception type that we can create in the script
|
17) an exception type that we can create in the script
|
||||||
|
@ -80,16 +76,12 @@ import std.json;
|
||||||
6) gotos? labels? labeled break/continue?
|
6) gotos? labels? labeled break/continue?
|
||||||
18) what about something like ruby's blocks or macros? parsing foo(arg) { code } is easy enough, but how would we use it?
|
18) what about something like ruby's blocks or macros? parsing foo(arg) { code } is easy enough, but how would we use it?
|
||||||
|
|
||||||
try is considered a statement right now and this only works on top level surrounded by {}
|
|
||||||
it should be usable anywhere
|
|
||||||
|
|
||||||
var FIXME:
|
var FIXME:
|
||||||
|
|
||||||
user defined operator overloading on objects, including opCall
|
user defined operator overloading on objects, including opCall, opApply, and more
|
||||||
flesh out prototype objects for Array, String, and Function
|
flesh out prototype objects for Array, String, and Function
|
||||||
|
|
||||||
opEquals and stricterOpEquals
|
looserOpEquals
|
||||||
opDispatch overriding
|
|
||||||
|
|
||||||
it would be nice if delegates on native types could work
|
it would be nice if delegates on native types could work
|
||||||
*/
|
*/
|
||||||
|
@ -471,14 +463,44 @@ struct var {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int opApply(int delegate(ref var) dg) {
|
public int opApply(scope int delegate(ref var) dg) {
|
||||||
if(this.payloadType() == Type.Array)
|
foreach(i, item; this)
|
||||||
foreach(ref v; this._payload._array)
|
if(auto result = dg(item))
|
||||||
if(auto result = dg(v))
|
return result;
|
||||||
return result;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int opApply(scope int delegate(var, ref var) dg) {
|
||||||
|
if(this.payloadType() == Type.Array) {
|
||||||
|
foreach(i, ref v; this._payload._array)
|
||||||
|
if(auto result = dg(var(i), v))
|
||||||
|
return result;
|
||||||
|
} else if(this.payloadType() == Type.Object && this._payload._object !is null) {
|
||||||
|
// FIXME: if it offers input range primitives, we should use them
|
||||||
|
// FIXME: user defined opApply on the object
|
||||||
|
foreach(k, ref v; this._payload._object._properties)
|
||||||
|
if(auto result = dg(var(k), v))
|
||||||
|
return result;
|
||||||
|
} else if(this.payloadType() == Type.String) {
|
||||||
|
// this is to prevent us from allocating a new string on each character, hopefully limiting that massively
|
||||||
|
static immutable string chars = makeAscii!();
|
||||||
|
|
||||||
|
foreach(i, dchar c; this._payload._string) {
|
||||||
|
var lol = "";
|
||||||
|
if(c < 128)
|
||||||
|
lol._payload._string = chars[c .. c + 1];
|
||||||
|
else
|
||||||
|
lol._payload._string = to!string(""d ~ c); // blargh, how slow can we go?
|
||||||
|
if(auto result = dg(var(i), lol))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// throw invalid foreach aggregate
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public T opCast(T)() {
|
public T opCast(T)() {
|
||||||
return this.get!T;
|
return this.get!T;
|
||||||
}
|
}
|
||||||
|
@ -611,7 +633,7 @@ struct var {
|
||||||
case Type.Object:
|
case Type.Object:
|
||||||
static if(isAssociativeArray!T) {
|
static if(isAssociativeArray!T) {
|
||||||
T ret;
|
T ret;
|
||||||
foreach(k, v; this._properties)
|
foreach(k, v; this._payload._object._properties)
|
||||||
ret[to!(KeyType!T)(k)] = v.get!(ValueType!T);
|
ret[to!(KeyType!T)(k)] = v.get!(ValueType!T);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1203,7 +1225,6 @@ class PrototypeObject {
|
||||||
if(possibleSecondary !is null) {
|
if(possibleSecondary !is null) {
|
||||||
curr = possibleSecondary;
|
curr = possibleSecondary;
|
||||||
if(!triedOne) {
|
if(!triedOne) {
|
||||||
writeln("trying again");
|
|
||||||
triedOne = true;
|
triedOne = true;
|
||||||
goto tryAgain;
|
goto tryAgain;
|
||||||
}
|
}
|
||||||
|
@ -1228,3 +1249,14 @@ class DynamicTypeException : Exception {
|
||||||
super(format("Tried to use %s as a %s", v.payloadType(), required), file, line);
|
super(format("Tried to use %s as a %s", v.payloadType(), required), file, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template makeAscii() {
|
||||||
|
string helper() {
|
||||||
|
string s;
|
||||||
|
foreach(i; 0 .. 128)
|
||||||
|
s ~= cast(char) i;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum makeAscii = helper();
|
||||||
|
}
|
||||||
|
|
164
script.d
164
script.d
|
@ -11,7 +11,11 @@
|
||||||
* mixin aka eval (does it at runtime, so more like eval than mixin, but I want it to look like D)
|
* mixin aka eval (does it at runtime, so more like eval than mixin, but I want it to look like D)
|
||||||
* scope guards, like in D
|
* scope guards, like in D
|
||||||
* try/catch/finally/throw
|
* try/catch/finally/throw
|
||||||
* for/while (foreach coming soon)
|
You can use try as an expression without any following catch to return the exception:
|
||||||
|
|
||||||
|
var a = try throw "exception";; // the double ; is because one closes the try, the second closes the var
|
||||||
|
// a is now the thrown exception
|
||||||
|
* for/while/foreach
|
||||||
* D style operators: +-/* on all numeric types, ~ on strings and arrays, |&^ on integers.
|
* D style operators: +-/* on all numeric types, ~ on strings and arrays, |&^ on integers.
|
||||||
Operators can coerce types as needed: 10 ~ "hey" == "10hey". 10 + "3" == 13.
|
Operators can coerce types as needed: 10 ~ "hey" == "10hey". 10 + "3" == 13.
|
||||||
Any math, except bitwise math, with a floating point component returns a floating point component, but pure int math is done as ints (unlike Javascript btw).
|
Any math, except bitwise math, with a floating point component returns a floating point component, but pure int math is done as ints (unlike Javascript btw).
|
||||||
|
@ -23,7 +27,18 @@
|
||||||
a = "" ~ a; // forces to string
|
a = "" ~ a; // forces to string
|
||||||
a = a+0.0; // coerces to float
|
a = a+0.0; // coerces to float
|
||||||
|
|
||||||
But I'll add nicer type stuff later. (maybe cast() actually)
|
Though casting is probably better.
|
||||||
|
* Type coercion via cast, similarly to D.
|
||||||
|
var a = "12";
|
||||||
|
a.typeof == "String";
|
||||||
|
a = cast(int) a;
|
||||||
|
a.typeof == "Integral";
|
||||||
|
a == 12;
|
||||||
|
|
||||||
|
Supported types for casting to: int/long (both actually an alias for long, because of how var works), float/double/real, string, char/dchar (these return *integral* types), and arrays, int[], string[], and float[].
|
||||||
|
|
||||||
|
This forwards directly to the D function var.opCast.
|
||||||
|
|
||||||
* some operator overloading on objects, passing opBinary(op, rhs), length, and perhaps others through like they would be in D.
|
* some operator overloading on objects, passing opBinary(op, rhs), length, and perhaps others through like they would be in D.
|
||||||
* if/else
|
* if/else
|
||||||
* array slicing, but note that slices are rvalues currently
|
* array slicing, but note that slices are rvalues currently
|
||||||
|
@ -42,14 +57,14 @@
|
||||||
static var b = 10;
|
static var b = 10;
|
||||||
|
|
||||||
// instance vars go on this instance itself
|
// instance vars go on this instance itself
|
||||||
var instance = 20;
|
var instancevar = 20;
|
||||||
|
|
||||||
// "virtual" functions can be overridden kinda like you expect in D, though there is no override keyword
|
// "virtual" functions can be overridden kinda like you expect in D, though there is no override keyword
|
||||||
function virt() {
|
function virt() {
|
||||||
b = 30; // lexical scoping is supported for static variables and functions
|
b = 30; // lexical scoping is supported for static variables and functions
|
||||||
|
|
||||||
// but be sure to use this. as a prefix for any class defined instance variables in here
|
// but be sure to use this. as a prefix for any class defined instance variables in here
|
||||||
this.instance = 10;
|
this.instancevar = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +97,10 @@
|
||||||
default arguments supported in any position
|
default arguments supported in any position
|
||||||
when calling, you can use the default keyword to use the default value in any position
|
when calling, you can use the default keyword to use the default value in any position
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FIXME:
|
||||||
|
* make sure superclass ctors are called
|
||||||
*/
|
*/
|
||||||
module arsd.script;
|
module arsd.script;
|
||||||
|
|
||||||
|
@ -144,7 +163,7 @@ private enum string[] keywords = [
|
||||||
"return", "static", "struct", "import", "module", "assert", "switch",
|
"return", "static", "struct", "import", "module", "assert", "switch",
|
||||||
"while", "catch", "throw", "scope", "break", "super", "class", "false", "mixin", "super",
|
"while", "catch", "throw", "scope", "break", "super", "class", "false", "mixin", "super",
|
||||||
"auto", // provided as an alias for var right now, may change later
|
"auto", // provided as an alias for var right now, may change later
|
||||||
"null", "else", "true", "eval", "goto", "enum", "case",
|
"null", "else", "true", "eval", "goto", "enum", "case", "cast",
|
||||||
"var", "for", "try", "new",
|
"var", "for", "try", "new",
|
||||||
"if", "do",
|
"if", "do",
|
||||||
];
|
];
|
||||||
|
@ -589,6 +608,24 @@ class FunctionLiteralExpression : Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CastExpression : Expression {
|
||||||
|
string type;
|
||||||
|
Expression e1;
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
return "cast(" ~ type ~ ") " ~ e1.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
override InterpretResult interpret(PrototypeObject sc) {
|
||||||
|
var n = e1.interpret(sc).value;
|
||||||
|
foreach(possibleType; CtList!("int", "long", "float", "double", "real", "char", "dchar", "string", "int[]", "string[]", "float[]")) {
|
||||||
|
if(type == possibleType)
|
||||||
|
n = mixin("cast(" ~ possibleType ~ ") n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return InterpretResult(n, sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class VariableDeclaration : Expression {
|
class VariableDeclaration : Expression {
|
||||||
string[] identifiers;
|
string[] identifiers;
|
||||||
|
@ -937,6 +974,52 @@ class ScopeExpression : Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ForeachExpression : Expression {
|
||||||
|
VariableDeclaration decl;
|
||||||
|
Expression subject;
|
||||||
|
Expression loopBody;
|
||||||
|
|
||||||
|
override InterpretResult interpret(PrototypeObject sc) {
|
||||||
|
var result;
|
||||||
|
|
||||||
|
assert(loopBody !is null);
|
||||||
|
|
||||||
|
auto loopScope = new PrototypeObject();
|
||||||
|
loopScope.prototype = sc;
|
||||||
|
|
||||||
|
InterpretResult.FlowControl flowControl;
|
||||||
|
|
||||||
|
static string doLoopBody() { return q{
|
||||||
|
if(decl.identifiers.length > 1) {
|
||||||
|
sc._getMember(decl.identifiers[0], false, false) = i;
|
||||||
|
sc._getMember(decl.identifiers[1], false, false) = item;
|
||||||
|
} else {
|
||||||
|
sc._getMember(decl.identifiers[0], false, false) = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = loopBody.interpret(loopScope);
|
||||||
|
result = res.value;
|
||||||
|
flowControl = res.flowControl;
|
||||||
|
if(flowControl == InterpretResult.FlowControl.Break)
|
||||||
|
break;
|
||||||
|
if(flowControl == InterpretResult.FlowControl.Return)
|
||||||
|
break;
|
||||||
|
//if(flowControl == InterpretResult.FlowControl.Continue)
|
||||||
|
// this is fine, we still want to do the advancement
|
||||||
|
};}
|
||||||
|
|
||||||
|
var what = subject.interpret(sc).value;
|
||||||
|
foreach(i, item; what) {
|
||||||
|
mixin(doLoopBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flowControl != InterpretResult.FlowControl.Return)
|
||||||
|
flowControl = InterpretResult.FlowControl.Normal;
|
||||||
|
|
||||||
|
return InterpretResult(result, sc, flowControl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ForExpression : Expression {
|
class ForExpression : Expression {
|
||||||
Expression initialization;
|
Expression initialization;
|
||||||
Expression condition;
|
Expression condition;
|
||||||
|
@ -1091,23 +1174,26 @@ class ExceptionBlockExpression : Expression {
|
||||||
assert(tryExpression !is null);
|
assert(tryExpression !is null);
|
||||||
assert(catchVarDecls.length == catchExpressions.length);
|
assert(catchVarDecls.length == catchExpressions.length);
|
||||||
|
|
||||||
if(catchExpressions.length)
|
if(catchExpressions.length || (catchExpressions.length == 0 && finallyExpressions.length == 0))
|
||||||
try {
|
try {
|
||||||
result = tryExpression.interpret(sc);
|
result = tryExpression.interpret(sc);
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
var ex = var.emptyObject;
|
||||||
|
ex.type = typeid(e).name;
|
||||||
|
ex.msg = e.msg;
|
||||||
|
ex.file = e.file;
|
||||||
|
ex.line = e.line;
|
||||||
|
|
||||||
// FIXME: this only allows one but it might be nice to actually do different types at some point
|
// FIXME: this only allows one but it might be nice to actually do different types at some point
|
||||||
|
if(catchExpressions.length)
|
||||||
foreach(i, ce; catchExpressions) {
|
foreach(i, ce; catchExpressions) {
|
||||||
auto catchScope = new PrototypeObject();
|
auto catchScope = new PrototypeObject();
|
||||||
catchScope.prototype = sc;
|
catchScope.prototype = sc;
|
||||||
var ex = var.emptyObject;
|
|
||||||
ex.type = typeid(e).name;
|
|
||||||
ex.msg = e.msg;
|
|
||||||
ex.file = e.file;
|
|
||||||
ex.line = e.line;
|
|
||||||
catchScope._getMember(catchVarDecls[i], false, false) = ex;
|
catchScope._getMember(catchVarDecls[i], false, false) = ex;
|
||||||
|
|
||||||
result = ce.interpret(catchScope);
|
result = ce.interpret(catchScope);
|
||||||
}
|
} else
|
||||||
|
result = InterpretResult(ex, sc);
|
||||||
} finally {
|
} finally {
|
||||||
foreach(fe; finallyExpressions)
|
foreach(fe; finallyExpressions)
|
||||||
result = fe.interpret(sc);
|
result = fe.interpret(sc);
|
||||||
|
@ -1451,7 +1537,7 @@ Expression parseAddend(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
return e1;
|
return e1;
|
||||||
case "=":
|
case "=":
|
||||||
tokens.popFront();
|
tokens.popFront();
|
||||||
return new AssignExpression(e1, parseAddend(tokens));
|
return new AssignExpression(e1, parseExpression(tokens));
|
||||||
case "~":
|
case "~":
|
||||||
// FIXME: make sure this has the right associativity
|
// FIXME: make sure this has the right associativity
|
||||||
|
|
||||||
|
@ -1497,11 +1583,15 @@ Expression parseAddend(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
return e1;
|
return e1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens, bool consumeEnd = false) {
|
||||||
Expression ret;
|
Expression ret;
|
||||||
ScriptToken first;
|
ScriptToken first;
|
||||||
string expectedEnd = ";";
|
string expectedEnd = ";";
|
||||||
//auto e1 = parseFactor(tokens);
|
//auto e1 = parseFactor(tokens);
|
||||||
|
|
||||||
|
while(tokens.peekNextToken(ScriptToken.Type.symbol, ";")) {
|
||||||
|
tokens.popFront();
|
||||||
|
}
|
||||||
if(!tokens.empty) {
|
if(!tokens.empty) {
|
||||||
first = tokens.front;
|
first = tokens.front;
|
||||||
if(tokens.peekNextToken(ScriptToken.Type.symbol, "{")) {
|
if(tokens.peekNextToken(ScriptToken.Type.symbol, "{")) {
|
||||||
|
@ -1532,7 +1622,7 @@ Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
literal.functionBody = parseExpression(tokens);
|
literal.functionBody = parseExpression(tokens);
|
||||||
|
|
||||||
auto e = new OpAssignExpression("~", new VariableExpression(i), literal);
|
auto e = new OpAssignExpression("~", new VariableExpression(i), literal);
|
||||||
return e;
|
ret = e;
|
||||||
} else if(tokens.peekNextToken(ScriptToken.Type.symbol, "(")) {
|
} else if(tokens.peekNextToken(ScriptToken.Type.symbol, "(")) {
|
||||||
auto start = tokens.front;
|
auto start = tokens.front;
|
||||||
tokens.popFront();
|
tokens.popFront();
|
||||||
|
@ -1590,6 +1680,10 @@ Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
|
|
||||||
auto classIdent = tokens.requireNextToken(ScriptToken.Type.identifier);
|
auto classIdent = tokens.requireNextToken(ScriptToken.Type.identifier);
|
||||||
|
|
||||||
|
expressions ~= new AssignExpression(
|
||||||
|
new DotVarExpression(new VariableExpression("__proto"), new VariableExpression("__classname")),
|
||||||
|
new StringLiteralExpression(classIdent.str));
|
||||||
|
|
||||||
if(tokens.peekNextToken(ScriptToken.Type.symbol, ":")) {
|
if(tokens.peekNextToken(ScriptToken.Type.symbol, ":")) {
|
||||||
tokens.popFront();
|
tokens.popFront();
|
||||||
auto inheritFrom = tokens.requireNextToken(ScriptToken.Type.identifier);
|
auto inheritFrom = tokens.requireNextToken(ScriptToken.Type.identifier);
|
||||||
|
@ -1692,6 +1786,33 @@ Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
e.ifFalse = parseExpression(tokens);
|
e.ifFalse = parseExpression(tokens);
|
||||||
}
|
}
|
||||||
ret = e;
|
ret = e;
|
||||||
|
} else if(tokens.peekNextToken(ScriptToken.Type.keyword, "foreach")) {
|
||||||
|
tokens.popFront();
|
||||||
|
auto e = new ForeachExpression();
|
||||||
|
tokens.requireNextToken(ScriptToken.Type.symbol, "(");
|
||||||
|
e.decl = parseVariableDeclaration(tokens, ";");
|
||||||
|
tokens.requireNextToken(ScriptToken.Type.symbol, ";");
|
||||||
|
e.subject = parseExpression(tokens);
|
||||||
|
tokens.requireNextToken(ScriptToken.Type.symbol, ")");
|
||||||
|
e.loopBody = parseExpression(tokens);
|
||||||
|
ret = e;
|
||||||
|
|
||||||
|
expectedEnd = "";
|
||||||
|
} else if(tokens.peekNextToken(ScriptToken.Type.keyword, "cast")) {
|
||||||
|
tokens.popFront();
|
||||||
|
auto e = new CastExpression();
|
||||||
|
|
||||||
|
tokens.requireNextToken(ScriptToken.Type.symbol, "(");
|
||||||
|
e.type = tokens.requireNextToken(ScriptToken.Type.identifier).str;
|
||||||
|
if(tokens.peekNextToken(ScriptToken.Type.symbol, "[")) {
|
||||||
|
e.type ~= "[]";
|
||||||
|
tokens.popFront();
|
||||||
|
tokens.requireNextToken(ScriptToken.Type.symbol, "]");
|
||||||
|
}
|
||||||
|
tokens.requireNextToken(ScriptToken.Type.symbol, ")");
|
||||||
|
|
||||||
|
e.e1 = parseExpression(tokens);
|
||||||
|
ret = e;
|
||||||
} else if(tokens.peekNextToken(ScriptToken.Type.keyword, "for")) {
|
} else if(tokens.peekNextToken(ScriptToken.Type.keyword, "for")) {
|
||||||
tokens.popFront();
|
tokens.popFront();
|
||||||
auto e = new ForExpression();
|
auto e = new ForExpression();
|
||||||
|
@ -1736,7 +1857,8 @@ Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
auto tryToken = tokens.front;
|
auto tryToken = tokens.front;
|
||||||
auto e = new ExceptionBlockExpression();
|
auto e = new ExceptionBlockExpression();
|
||||||
tokens.popFront();
|
tokens.popFront();
|
||||||
e.tryExpression = parseExpression(tokens);
|
e.tryExpression = parseExpression(tokens, true);
|
||||||
|
|
||||||
bool hadSomething = false;
|
bool hadSomething = false;
|
||||||
while(tokens.peekNextToken(ScriptToken.Type.keyword, "catch")) {
|
while(tokens.peekNextToken(ScriptToken.Type.keyword, "catch")) {
|
||||||
if(hadSomething)
|
if(hadSomething)
|
||||||
|
@ -1757,8 +1879,8 @@ Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
e.finallyExpressions ~= parseExpression(tokens);
|
e.finallyExpressions ~= parseExpression(tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!hadSomething)
|
//if(!hadSomething)
|
||||||
throw new ScriptCompileException("Parse error, missing finally or catch after try", tryToken.lineNumber);
|
//throw new ScriptCompileException("Parse error, missing finally or catch after try", tryToken.lineNumber);
|
||||||
|
|
||||||
ret = e;
|
ret = e;
|
||||||
} else
|
} else
|
||||||
|
@ -1774,7 +1896,9 @@ Expression parseExpression(MyTokenStreamHere)(ref MyTokenStreamHere tokens) {
|
||||||
if(tokens.empty)
|
if(tokens.empty)
|
||||||
throw new ScriptCompileException("Parse error, unexpected end of input when reading expression", first.lineNumber);
|
throw new ScriptCompileException("Parse error, unexpected end of input when reading expression", first.lineNumber);
|
||||||
|
|
||||||
if(expectedEnd.length) {
|
if(expectedEnd.length && consumeEnd) {
|
||||||
|
if(tokens.peekNextToken(ScriptToken.Type.symbol, expectedEnd))
|
||||||
|
tokens.popFront();
|
||||||
// FIXME
|
// FIXME
|
||||||
//if(tokens.front.type != ScriptToken.Type.symbol && tokens.front.str != expectedEnd)
|
//if(tokens.front.type != ScriptToken.Type.symbol && tokens.front.str != expectedEnd)
|
||||||
//throw new ScriptCompileException("Parse error, missing "~expectedEnd~" at end of expression (starting on "~to!string(first.lineNumber)~"). Saw "~tokens.front.str~" instead", tokens.front.lineNumber);
|
//throw new ScriptCompileException("Parse error, missing "~expectedEnd~" at end of expression (starting on "~to!string(first.lineNumber)~"). Saw "~tokens.front.str~" instead", tokens.front.lineNumber);
|
||||||
|
@ -1901,6 +2025,8 @@ Expression parseStatement(MyTokenStreamHere)(ref MyTokenStreamHere tokens, strin
|
||||||
case "{":
|
case "{":
|
||||||
case "scope":
|
case "scope":
|
||||||
|
|
||||||
|
case "cast":
|
||||||
|
|
||||||
// classes
|
// classes
|
||||||
case "class":
|
case "class":
|
||||||
case "new":
|
case "new":
|
||||||
|
|
Loading…
Reference in New Issue