mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 18:32:03 +00:00
NTSL code cleanup.
This commit is contained in:
@@ -5,10 +5,10 @@
|
||||
|
||||
/*
|
||||
Macros: Expression Macros
|
||||
OPERATOR - A value indicating the parser currently expects a binary operator.
|
||||
VALUE - A value indicating the parser currently expects a value.
|
||||
SHIFT - Tells the parser to push the current operator onto the stack.
|
||||
REDUCE - Tells the parser to reduce the stack.
|
||||
OPERATOR - A value indicating the parser currently expects a binary operator.
|
||||
VALUE - A value indicating the parser currently expects a value.
|
||||
SHIFT - Tells the parser to push the current operator onto the stack.
|
||||
REDUCE - Tells the parser to reduce the stack.
|
||||
*/
|
||||
#define OPERATOR 1
|
||||
#define VALUE 2
|
||||
@@ -18,63 +18,71 @@
|
||||
/*
|
||||
Class: nS_Parser
|
||||
*/
|
||||
/n_Parser/nS_Parser
|
||||
var
|
||||
/datum/n_Parser/nS_Parser
|
||||
/*
|
||||
Var: expecting
|
||||
A variable which keeps track of whether an operator or value is expected. It should be either <OPERATOR> or <VALUE>. See <ParseExpression()>
|
||||
for more information.
|
||||
*/
|
||||
expecting=VALUE
|
||||
var/expecting = VALUE
|
||||
|
||||
proc
|
||||
/*
|
||||
Proc: Precedence
|
||||
Compares two operators, decides which is higher in the order of operations, and returns <SHIFT> or <REDUCE>.
|
||||
*/
|
||||
Precedence(node/expression/operator/top, node/expression/operator/input)
|
||||
if(istype(top))
|
||||
top=top.precedence
|
||||
if(istype(input))
|
||||
input=input:precedence
|
||||
if(top>=input)
|
||||
return REDUCE
|
||||
return SHIFT
|
||||
/datum/n_Parser/nS_Parser/proc/Precedence(var/datum/node/expression/operator/top, var/datum/node/expression/operator/input)
|
||||
if(istype(top))
|
||||
top = top.precedence
|
||||
|
||||
if(istype(input))
|
||||
|
||||
input = input:precedence
|
||||
|
||||
if(top >= input)
|
||||
return REDUCE
|
||||
|
||||
return SHIFT
|
||||
|
||||
/*
|
||||
Proc: GetExpression
|
||||
Takes a token expected to represent a value and returns an <expression> node.
|
||||
*/
|
||||
GetExpression(token/T)
|
||||
if(!T) return
|
||||
if(istype(T, /node/expression))
|
||||
return T
|
||||
switch(T.type)
|
||||
if(/token/word)
|
||||
return new/node/expression/value/variable(T.value)
|
||||
if(/token/accessor)
|
||||
var
|
||||
token/accessor/A=T
|
||||
node/expression/value/variable/E//=new(A.member)
|
||||
stack/S=new()
|
||||
while(istype(A.object, /token/accessor))
|
||||
S.Push(A)
|
||||
A=A.object
|
||||
ASSERT(istext(A.object))
|
||||
/datum/n_Parser/nS_Parser/proc/GetExpression(var/datum/token/T)
|
||||
if(!T)
|
||||
return
|
||||
|
||||
while(A)
|
||||
var/node/expression/value/variable/V=new()
|
||||
V.id=new(A.member)
|
||||
if(E)
|
||||
V.object=E
|
||||
else
|
||||
V.object=new/node/identifier(A.object)
|
||||
E=V
|
||||
A=S.Pop()
|
||||
return E
|
||||
if(istype(T, /datum/node/expression))
|
||||
return T
|
||||
|
||||
if(/token/number, /token/string)
|
||||
return new/node/expression/value/literal(T.value)
|
||||
switch(T.type)
|
||||
if(/datum/token/word)
|
||||
return new/datum/node/expression/value/variable(T.value)
|
||||
|
||||
if(/datum/token/accessor)
|
||||
var/datum/token/accessor/A = T
|
||||
var/datum/node/expression/value/variable/E// = new(A.member)
|
||||
var/datum/stack/S = new()
|
||||
|
||||
while(istype(A.object, /datum/token/accessor))
|
||||
S.Push(A)
|
||||
A = A.object
|
||||
|
||||
ASSERT(istext(A.object))
|
||||
|
||||
while(A)
|
||||
var/datum/node/expression/value/variable/V = new()
|
||||
V.id = new(A.member)
|
||||
if(E)
|
||||
V.object = E
|
||||
else
|
||||
V.object = new/datum/node/identifier(A.object)
|
||||
|
||||
E = V
|
||||
A = S.Pop()
|
||||
return E
|
||||
|
||||
if(/datum/token/number, /datum/token/string)
|
||||
return new/datum/node/expression/value/literal(T.value)
|
||||
|
||||
/*
|
||||
Proc: GetOperator
|
||||
@@ -91,15 +99,26 @@
|
||||
- <GetBinaryOperator()>
|
||||
- <GetUnaryOperator()>
|
||||
*/
|
||||
GetOperator(O, type=/node/expression/operator, L[])
|
||||
if(istype(O, type)) return O //O is already the desired type
|
||||
if(istype(O, /token)) O=O:value //sets O to text
|
||||
if(istext(O)) //sets O to path
|
||||
if(L.Find(O)) O=L[O]
|
||||
else return null
|
||||
if(ispath(O))O=new O //catches path from last check
|
||||
else return null //Unknown type
|
||||
return O
|
||||
/datum/n_Parser/nS_Parser/proc/GetOperator(O, type = /datum/node/expression/operator, L[])
|
||||
if(istype(O, type))
|
||||
return O //O is already the desired type
|
||||
|
||||
if(istype(O, /datum/token))
|
||||
O = O:value //sets O to text
|
||||
|
||||
if(istext(O)) //sets O to path
|
||||
if(L.Find(O))
|
||||
O = L[O]
|
||||
else
|
||||
return null
|
||||
|
||||
if(ispath(O))
|
||||
O = new O //catches path from last check
|
||||
|
||||
else
|
||||
return null //Unknown type
|
||||
|
||||
return O
|
||||
|
||||
/*
|
||||
Proc: GetBinaryOperator
|
||||
@@ -110,8 +129,8 @@
|
||||
- <GetOperator()>
|
||||
- <GetUnaryOperator()>
|
||||
*/
|
||||
GetBinaryOperator(O)
|
||||
return GetOperator(O, /node/expression/operator/binary, options.binary_operators)
|
||||
/datum/n_Parser/nS_Parser/proc/GetBinaryOperator(O)
|
||||
return GetOperator(O, /datum/node/expression/operator/binary, options.binary_operators)
|
||||
|
||||
/*
|
||||
Proc: GetUnaryOperator
|
||||
@@ -122,30 +141,34 @@
|
||||
- <GetOperator()>
|
||||
- <GetBinaryOperator()>
|
||||
*/
|
||||
GetUnaryOperator(O)
|
||||
return GetOperator(O, /node/expression/operator/unary, options.unary_operators)
|
||||
/datum/n_Parser/nS_Parser/proc/GetUnaryOperator(O)
|
||||
return GetOperator(O, /datum/node/expression/operator/unary, options.unary_operators)
|
||||
|
||||
/*
|
||||
Proc: Reduce
|
||||
Takes the operator on top of the opr stack and assigns its operand(s). Then this proc pushes the value of that operation to the top
|
||||
of the val stack.
|
||||
*/
|
||||
Reduce(stack/opr, stack/val)
|
||||
var/node/expression/operator/O=opr.Pop()
|
||||
if(!O) return
|
||||
if(!istype(O))
|
||||
errors+=new/scriptError("Error reducing expression - invalid operator.")
|
||||
return
|
||||
//Take O and assign its operands, popping one or two values from the val stack
|
||||
//depending on whether O is a binary or unary operator.
|
||||
if(istype(O, /node/expression/operator/binary))
|
||||
var/node/expression/operator/binary/B=O
|
||||
B.exp2=val.Pop()
|
||||
B.exp =val.Pop()
|
||||
val.Push(B)
|
||||
else
|
||||
O.exp=val.Pop()
|
||||
val.Push(O)
|
||||
/datum/n_Parser/nS_Parser/proc/Reduce(var/datum/stack/opr, var/datum/stack/val)
|
||||
var/datum/node/expression/operator/O = opr.Pop()
|
||||
if(!O)
|
||||
return
|
||||
|
||||
if(!istype(O))
|
||||
errors += new/datum/scriptError("Error reducing expression - invalid operator.")
|
||||
return
|
||||
|
||||
//Take O and assign its operands, popping one or two values from the val stack
|
||||
//depending on whether O is a binary or unary operator.
|
||||
if(istype(O, /datum/node/expression/operator/binary))
|
||||
var/datum/node/expression/operator/binary/B=O
|
||||
B.exp2 = val.Pop()
|
||||
B.exp = val.Pop()
|
||||
val.Push(B)
|
||||
|
||||
else
|
||||
O.exp=val.Pop()
|
||||
val.Push(O)
|
||||
|
||||
/*
|
||||
Proc: EndOfExpression
|
||||
@@ -154,14 +177,14 @@
|
||||
Parameters:
|
||||
end - A list of values to compare the current token to.
|
||||
*/
|
||||
EndOfExpression(end[])
|
||||
if(!curToken)
|
||||
return 1
|
||||
if(istype(curToken, /token/symbol) && end.Find(curToken.value))
|
||||
return 1
|
||||
if(istype(curToken, /token/end) && end.Find(/token/end))
|
||||
return 1
|
||||
return 0
|
||||
/datum/n_Parser/nS_Parser/proc/EndOfExpression(end[])
|
||||
if(!curToken)
|
||||
return 1
|
||||
if(istype(curToken, /datum/token/symbol) && end.Find(curToken.value))
|
||||
return 1
|
||||
if(istype(curToken, /datum/token/end) && end.Find(/datum/token/end))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/*
|
||||
Proc: ParseExpression
|
||||
@@ -180,106 +203,114 @@
|
||||
- <ParseParenExpression()>
|
||||
- <ParseParamExpression()>
|
||||
*/
|
||||
ParseExpression(list/end=list(/token/end), list/ErrChars=list("{", "}"), check_functions = 0)
|
||||
var/stack
|
||||
opr=new
|
||||
val=new
|
||||
src.expecting=VALUE
|
||||
var/loop = 0
|
||||
for()
|
||||
loop++
|
||||
if(loop > 800)
|
||||
errors+=new/scriptError("Too many nested tokens.")
|
||||
return
|
||||
|
||||
if(EndOfExpression(end))
|
||||
break
|
||||
if(istype(curToken, /token/symbol) && ErrChars.Find(curToken.value))
|
||||
errors+=new/scriptError/BadToken(curToken)
|
||||
break
|
||||
/datum/n_Parser/nS_Parser/proc/ParseExpression(var/list/end = list(/datum/token/end), list/ErrChars = list("{", "}"), check_functions = 0)
|
||||
var/datum/stack/opr = new
|
||||
var/datum/stack/val = new
|
||||
src.expecting = VALUE
|
||||
var/loop = 0
|
||||
for()
|
||||
loop++
|
||||
if(loop > 800)
|
||||
errors += new/datum/scriptError("Too many nested tokens.")
|
||||
return
|
||||
|
||||
if(EndOfExpression(end))
|
||||
break
|
||||
|
||||
if(index>tokens.len) //End of File
|
||||
errors+=new/scriptError/EndOfFile()
|
||||
break
|
||||
var/token/ntok
|
||||
if(index+1<=tokens.len)
|
||||
ntok=tokens[index+1]
|
||||
if(istype(curToken, /datum/token/symbol) && ErrChars.Find(curToken.value))
|
||||
errors += new/datum/scriptError/BadToken(curToken)
|
||||
break
|
||||
|
||||
if(istype(curToken, /token/symbol) && curToken.value=="(") //Parse parentheses expression
|
||||
if(expecting!=VALUE)
|
||||
errors+=new/scriptError/ExpectedToken("operator", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
val.Push(ParseParenExpression())
|
||||
if(index > tokens.len) //End of File
|
||||
errors += new/datum/scriptError/EndOfFile()
|
||||
break
|
||||
|
||||
else if(istype(curToken, /token/symbol)) //Operator found.
|
||||
var/node/expression/operator/curOperator //Figure out whether it is unary or binary and get a new instance.
|
||||
if(src.expecting==OPERATOR)
|
||||
curOperator=GetBinaryOperator(curToken)
|
||||
if(!curOperator)
|
||||
errors+=new/scriptError/ExpectedToken("operator", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
else
|
||||
curOperator=GetUnaryOperator(curToken)
|
||||
if(!curOperator) //given symbol isn't a unary operator
|
||||
errors+=new/scriptError/ExpectedToken("expression", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
var/datum/token/ntok
|
||||
if(index + 1 <= tokens.len)
|
||||
ntok = tokens[index + 1]
|
||||
|
||||
if(opr.Top() && Precedence(opr.Top(), curOperator)==REDUCE) //Check order of operations and reduce if necessary
|
||||
Reduce(opr, val)
|
||||
continue
|
||||
opr.Push(curOperator)
|
||||
src.expecting=VALUE
|
||||
if(istype(curToken, /datum/token/symbol) && curToken.value == "(") //Parse parentheses expression
|
||||
if(expecting != VALUE)
|
||||
errors += new/datum/scriptError/ExpectedToken("operator", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
|
||||
else if(ntok && ntok.value=="(" && istype(ntok, /token/symbol)\
|
||||
&& istype(curToken, /token/word)) //Parse function call
|
||||
val.Push(ParseParenExpression())
|
||||
|
||||
if(!check_functions)
|
||||
|
||||
var/token/preToken=curToken
|
||||
var/old_expect=src.expecting
|
||||
var/fex=ParseFunctionExpression()
|
||||
if(old_expect!=VALUE)
|
||||
errors+=new/scriptError/ExpectedToken("operator", preToken)
|
||||
NextToken()
|
||||
continue
|
||||
val.Push(fex)
|
||||
else
|
||||
errors+=new/scriptError/ParameterFunction(curToken)
|
||||
break
|
||||
|
||||
else if(istype(curToken, /token/keyword)) //inline keywords
|
||||
var/n_Keyword/kw=options.keywords[curToken.value]
|
||||
kw=new kw(inline=1)
|
||||
if(kw)
|
||||
if(!kw.Parse(src))
|
||||
return
|
||||
else
|
||||
errors+=new/scriptError/BadToken(curToken)
|
||||
|
||||
else if(istype(curToken, /token/end)) //semicolon found where it wasn't expected
|
||||
errors+=new/scriptError/BadToken(curToken)
|
||||
else if(istype(curToken, /datum/token/symbol)) //Operator found.
|
||||
var/datum/node/expression/operator/curOperator //Figure out whether it is unary or binary and get a new instance.
|
||||
if(src.expecting == OPERATOR)
|
||||
curOperator = GetBinaryOperator(curToken)
|
||||
if(!curOperator)
|
||||
errors += new/datum/scriptError/ExpectedToken("operator", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
else
|
||||
curOperator = GetUnaryOperator(curToken)
|
||||
if(!curOperator) //given symbol isn't a unary operator
|
||||
errors += new/datum/scriptError/ExpectedToken("expression", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
else
|
||||
if(expecting!=VALUE)
|
||||
errors+=new/scriptError/ExpectedToken("operator", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
val.Push(GetExpression(curToken))
|
||||
src.expecting=OPERATOR
|
||||
|
||||
if(opr.Top() && Precedence(opr.Top(), curOperator) == REDUCE) //Check order of operations and reduce if necessary
|
||||
Reduce(opr, val)
|
||||
continue
|
||||
|
||||
opr.Push(curOperator)
|
||||
src.expecting = VALUE
|
||||
|
||||
else if(ntok && ntok.value == "(" && istype(ntok, /datum/token/symbol)\
|
||||
&& istype(curToken, /datum/token/word)) //Parse function call
|
||||
|
||||
if(!check_functions)
|
||||
|
||||
var/datum/token/preToken = curToken
|
||||
var/old_expect = src.expecting
|
||||
var/fex = ParseFunctionExpression()
|
||||
if(old_expect != VALUE)
|
||||
errors += new/datum/scriptError/ExpectedToken("operator", preToken)
|
||||
NextToken()
|
||||
continue
|
||||
|
||||
val.Push(fex)
|
||||
else
|
||||
errors += new/datum/scriptError/ParameterFunction(curToken)
|
||||
break
|
||||
|
||||
else if(istype(curToken, /datum/token/keyword)) //inline keywords
|
||||
var/datum/n_Keyword/kw = options.keywords[curToken.value]
|
||||
kw = new kw(inline=1)
|
||||
if(kw)
|
||||
if(!kw.Parse(src))
|
||||
return
|
||||
else
|
||||
errors += new/datum/scriptError/BadToken(curToken)
|
||||
|
||||
else if(istype(curToken, /datum/token/end)) //semicolon found where it wasn't expected
|
||||
errors += new/datum/scriptError/BadToken(curToken)
|
||||
NextToken()
|
||||
continue
|
||||
else
|
||||
if(expecting != VALUE)
|
||||
errors += new/datum/scriptError/ExpectedToken("operator", curToken)
|
||||
NextToken()
|
||||
continue
|
||||
|
||||
while(opr.Top()) Reduce(opr, val) //Reduce the value stack completely
|
||||
.=val.Pop() //Return what should be the last value on the stack
|
||||
if(val.Top()) //
|
||||
var/node/N=val.Pop()
|
||||
errors+=new/scriptError("Error parsing expression. Unexpected value left on stack: [N.ToString()].")
|
||||
return null
|
||||
val.Push(GetExpression(curToken))
|
||||
src.expecting = OPERATOR
|
||||
|
||||
NextToken()
|
||||
|
||||
while(opr.Top())
|
||||
Reduce(opr, val)
|
||||
//Reduce the value stack completely
|
||||
. = val.Pop() //Return what should be the last value on the stack
|
||||
|
||||
if(val.Top()) //
|
||||
var/datum/node/N = val.Pop()
|
||||
errors += new/datum/scriptError("Error parsing expression. Unexpected value left on stack: [N.ToString()].")
|
||||
return null
|
||||
|
||||
/*
|
||||
Proc: ParseFunctionExpression
|
||||
@@ -288,29 +319,33 @@
|
||||
See Also:
|
||||
- <ParseExpression()>
|
||||
*/
|
||||
ParseFunctionExpression()
|
||||
var/node/expression/FunctionCall/exp=new
|
||||
exp.func_name=curToken.value
|
||||
NextToken() //skip function name
|
||||
NextToken() //skip open parenthesis, already found
|
||||
var/loops = 0
|
||||
|
||||
for()
|
||||
loops++
|
||||
if(loops>=800)
|
||||
errors += new/scriptError("Too many nested expressions.")
|
||||
break
|
||||
//CRASH("Something TERRIBLE has gone wrong in ParseFunctionExpression ;__;")
|
||||
/datum/n_Parser/nS_Parser/proc/ParseFunctionExpression()
|
||||
var/datum/node/expression/FunctionCall/exp = new
|
||||
exp.func_name = curToken.value
|
||||
NextToken() //skip function name
|
||||
NextToken() //skip open parenthesis, already found
|
||||
var/loops = 0
|
||||
|
||||
if(istype(curToken, /token/symbol) && curToken.value==")")
|
||||
return exp
|
||||
exp.parameters+=ParseParamExpression()
|
||||
if(errors.len)
|
||||
return exp
|
||||
if(curToken.value==","&&istype(curToken, /token/symbol))NextToken() //skip comma
|
||||
if(istype(curToken, /token/end)) //Prevents infinite loop...
|
||||
errors+=new/scriptError/ExpectedToken(")")
|
||||
return exp
|
||||
for()
|
||||
loops++
|
||||
if(loops >= 800)
|
||||
errors += new/datum/scriptError("Too many nested expressions.")
|
||||
break
|
||||
//CRASH("Something TERRIBLE has gone wrong in ParseFunctionExpression ;__;")
|
||||
|
||||
if(istype(curToken, /datum/token/symbol) && curToken.value == ")")
|
||||
return exp
|
||||
exp.parameters += ParseParamExpression()
|
||||
if(errors.len)
|
||||
return exp
|
||||
|
||||
if(curToken.value == "," && istype(curToken, /datum/token/symbol))
|
||||
NextToken() //skip comma
|
||||
|
||||
if(istype(curToken, /datum/token/end)) //Prevents infinite loop...
|
||||
errors += new/datum/scriptError/ExpectedToken(")")
|
||||
return exp
|
||||
|
||||
/*
|
||||
Proc: ParseParenExpression
|
||||
@@ -319,10 +354,10 @@
|
||||
See Also:
|
||||
- <ParseExpression()>
|
||||
*/
|
||||
ParseParenExpression()
|
||||
if(!CheckToken("(", /token/symbol))
|
||||
return
|
||||
return new/node/expression/operator/unary/group(ParseExpression(list(")")))
|
||||
/datum/n_Parser/nS_Parser/proc/ParseParenExpression()
|
||||
if(!CheckToken("(", /datum/token/symbol))
|
||||
return
|
||||
return new/datum/node/expression/operator/unary/group(ParseExpression(list(")")))
|
||||
|
||||
/*
|
||||
Proc: ParseParamExpression
|
||||
@@ -331,6 +366,6 @@
|
||||
See Also:
|
||||
- <ParseExpression()>
|
||||
*/
|
||||
ParseParamExpression(var/check_functions = 0)
|
||||
var/cf = check_functions
|
||||
return ParseExpression(list(",", ")"), check_functions = cf)
|
||||
/datum/n_Parser/nS_Parser/proc/ParseParamExpression(var/check_functions = 0)
|
||||
var/cf = check_functions
|
||||
return ParseExpression(list(",", ")"), check_functions = cf)
|
||||
@@ -12,17 +12,17 @@ var/const/KW_WARN = 3 //Warning
|
||||
var/const/Class: n_Keyword
|
||||
var/const/Represents a special statement in the code triggered by a keyword.
|
||||
*/
|
||||
/n_Keyword
|
||||
New(inline=0)
|
||||
src.inline=inline
|
||||
return ..()
|
||||
|
||||
/datum/n_Keyword
|
||||
/*
|
||||
Var: inline
|
||||
1 if the keyword is in an expression (e.g. the new keyword in many languages), 0 otherwise (such as the if and else keywords).
|
||||
*/
|
||||
var/inline
|
||||
|
||||
/datum/n_Keyword/New(inline = 0)
|
||||
src.inline = inline
|
||||
return ..()
|
||||
|
||||
/*
|
||||
Proc: Parse
|
||||
Called when the parser finds a keyword in the code.
|
||||
@@ -31,9 +31,8 @@ var/const/Represents a special statement in the code triggered by a keyword.
|
||||
parser - The parser that created this object. You can use the parameter to manipulate the parser in order to add statements and blocks
|
||||
to its AST.
|
||||
*/
|
||||
proc/Parse(n_Parser/parser)
|
||||
//writepanic("[__FILE__].[__LINE__] ([src.type])([usr ? usr.ckey : ""]) \\proc/Parse() called tick#: [world.time]")
|
||||
|
||||
/datum/n_Keyword/proc/Parse(var/datum/n_Parser/parser)
|
||||
return
|
||||
/*
|
||||
Class: nS_Keyword
|
||||
A keyword in n_Script. By default these include return, if, else, while, and def. To enable or disable a keyword, change the
|
||||
@@ -43,150 +42,163 @@ var/const/Represents a special statement in the code triggered by a keyword.
|
||||
When a parser is expecting a new statement, and a keyword listed in <nS_Options.keywords> is found, it will call the keyword's
|
||||
<n_Keyword.Parse()> proc.
|
||||
*/
|
||||
//
|
||||
nS_Keyword
|
||||
New(inline=0)
|
||||
if(inline)
|
||||
del src
|
||||
/datum/n_Keyword/nS_Keyword/New(var/inline = 0)
|
||||
if(inline)
|
||||
del src
|
||||
|
||||
kwReturn
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock)) // Exit out of the program by setting the tokens list size to the same as index.
|
||||
parser.tokens.len = parser.index
|
||||
return
|
||||
var/node/statement/ReturnStatement/stmt=new
|
||||
parser.NextToken() //skip 'return' token
|
||||
stmt.value=parser.ParseExpression()
|
||||
parser.curBlock.statements+=stmt
|
||||
/datum/n_Keyword/nS_Keyword/kwReturn/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
if(istype(parser.curBlock, /datum/node/BlockDefinition/GlobalBlock)) // Exit out of the program by setting the tokens list size to the same as index.
|
||||
parser.tokens.len = parser.index
|
||||
return
|
||||
|
||||
kwIf
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
var/node/statement/IfStatement/stmt=new
|
||||
parser.NextToken() //skip 'if' token
|
||||
stmt.cond=parser.ParseParenExpression()
|
||||
if(!parser.CheckToken(")", /token/symbol))
|
||||
return KW_FAIL
|
||||
if(!parser.CheckToken("{", /token/symbol, skip=0)) //Token needs to be preserved for parse loop, so skip=0
|
||||
return KW_ERR
|
||||
parser.curBlock.statements+=stmt
|
||||
stmt.block=new
|
||||
parser.AddBlock(stmt.block)
|
||||
var/datum/node/statement/ReturnStatement/stmt = new
|
||||
parser.NextToken() //skip 'return' token
|
||||
stmt.value = parser.ParseExpression()
|
||||
parser.curBlock.statements += stmt
|
||||
|
||||
kwElseIf
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
var/list/L=parser.curBlock.statements
|
||||
var/node/statement/IfStatement/ifstmt
|
||||
/datum/n_Keyword/nS_Keyword/kwIf/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
var/datum/node/statement/IfStatement/stmt = new
|
||||
parser.NextToken() //skip 'if' token
|
||||
stmt.cond = parser.ParseParenExpression()
|
||||
if(!parser.CheckToken(")", /datum/token/symbol))
|
||||
return KW_FAIL
|
||||
|
||||
if(L && L.len)
|
||||
ifstmt = L[L.len] //Get the last statement in the current block
|
||||
if(!ifstmt || !istype(ifstmt) || ifstmt.else_if)
|
||||
parser.errors += new/scriptError/ExpectedToken("if statement", parser.curToken)
|
||||
return KW_FAIL
|
||||
if(!parser.CheckToken("{", /datum/token/symbol, skip=0)) //Token needs to be preserved for parse loop, so skip=0
|
||||
return KW_ERR
|
||||
|
||||
var/node/statement/IfStatement/ElseIf/stmt = new
|
||||
parser.NextToken() //skip 'if' token
|
||||
stmt.cond = parser.ParseParenExpression()
|
||||
if(!parser.CheckToken(")", /token/symbol))
|
||||
return KW_FAIL
|
||||
if(!parser.CheckToken("{", /token/symbol, skip=0)) //Token needs to be preserved for parse loop, so skip=0
|
||||
return KW_ERR
|
||||
parser.curBlock.statements+=stmt
|
||||
stmt.block=new
|
||||
ifstmt.else_if = stmt
|
||||
parser.AddBlock(stmt.block)
|
||||
parser.curBlock.statements += stmt
|
||||
stmt.block = new
|
||||
parser.AddBlock(stmt.block)
|
||||
|
||||
/datum/n_Keyword/nS_Keyword/kwElseIf/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
var/list/L = parser.curBlock.statements
|
||||
var/datum/node/statement/IfStatement/ifstmt
|
||||
|
||||
kwElse
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
var/list/L=parser.curBlock.statements
|
||||
var/node/statement/IfStatement/stmt
|
||||
if(L&&L.len) stmt=L[L.len] //Get the last statement in the current block
|
||||
if(!stmt || !istype(stmt) || stmt.else_block) //Ensure that it is an if statement
|
||||
parser.errors+=new/scriptError/ExpectedToken("if statement",parser.curToken)
|
||||
return KW_FAIL
|
||||
parser.NextToken() //skip 'else' token
|
||||
if(!parser.CheckToken("{", /token/symbol, skip=0))
|
||||
return KW_ERR
|
||||
stmt.else_block=new()
|
||||
parser.AddBlock(stmt.else_block)
|
||||
if(L && L.len)
|
||||
ifstmt = L[L.len] //Get the last statement in the current block
|
||||
|
||||
kwWhile
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
var/node/statement/WhileLoop/stmt=new
|
||||
parser.NextToken() //skip 'while' token
|
||||
stmt.cond=parser.ParseParenExpression()
|
||||
if(!parser.CheckToken(")", /token/symbol))
|
||||
return KW_FAIL
|
||||
if(!parser.CheckToken("{", /token/symbol, skip=0))
|
||||
return KW_ERR
|
||||
parser.curBlock.statements+=stmt
|
||||
stmt.block=new
|
||||
parser.AddBlock(stmt.block)
|
||||
if(!ifstmt || !istype(ifstmt) || ifstmt.else_if)
|
||||
usr << "NTSL: ELSE IF FAILED: [!ifstmt], [!istype(ifstmt)], [!istype(ifstmt) || ifstmt.else_if]" // Usr is unsafe as SHIT but JUST incase I forget this debug line like the fucking asset cache...
|
||||
parser.errors += new/datum/scriptError/ExpectedToken("if statement", parser.curToken)
|
||||
return KW_FAIL
|
||||
|
||||
kwBreak
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
|
||||
parser.errors+=new/scriptError/BadToken(parser.curToken)
|
||||
. = KW_WARN
|
||||
var/node/statement/BreakStatement/stmt=new
|
||||
parser.NextToken() //skip 'break' token
|
||||
parser.curBlock.statements+=stmt
|
||||
var/datum/node/statement/IfStatement/ElseIf/stmt = new
|
||||
parser.NextToken() //skip 'if' token
|
||||
stmt.cond = parser.ParseParenExpression()
|
||||
if(!parser.CheckToken(")", /datum/token/symbol))
|
||||
return KW_FAIL
|
||||
|
||||
kwContinue
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
if(istype(parser.curBlock, /node/BlockDefinition/GlobalBlock))
|
||||
parser.errors+=new/scriptError/BadToken(parser.curToken)
|
||||
. = KW_WARN
|
||||
var/node/statement/ContinueStatement/stmt=new
|
||||
parser.NextToken() //skip 'break' token
|
||||
parser.curBlock.statements+=stmt
|
||||
if(!parser.CheckToken("{", /datum/token/symbol, skip = 0)) //Token needs to be preserved for parse loop, so skip=0
|
||||
return KW_ERR
|
||||
|
||||
kwDef
|
||||
Parse(n_Parser/nS_Parser/parser)
|
||||
.=KW_PASS
|
||||
var/node/statement/FunctionDefinition/def=new
|
||||
parser.NextToken() //skip 'def' token
|
||||
if(!parser.options.IsValidID(parser.curToken.value))
|
||||
parser.errors+=new/scriptError/InvalidID(parser.curToken)
|
||||
return KW_FAIL
|
||||
def.func_name=parser.curToken.value
|
||||
parser.NextToken()
|
||||
if(!parser.CheckToken("(", /token/symbol))
|
||||
return KW_FAIL
|
||||
for() //for now parameters can be separated by whitespace - they don't need a comma in between
|
||||
if(istype(parser.curToken, /token/symbol))
|
||||
switch(parser.curToken.value)
|
||||
if(",")
|
||||
parser.NextToken()
|
||||
if(")")
|
||||
break
|
||||
else
|
||||
parser.errors+=new/scriptError/BadToken(parser.curToken)
|
||||
return KW_ERR
|
||||
parser.curBlock.statements += stmt
|
||||
stmt.block = new
|
||||
ifstmt.else_if = stmt
|
||||
parser.AddBlock(stmt.block)
|
||||
|
||||
else if(istype(parser.curToken, /token/word))
|
||||
def.parameters+=parser.curToken.value
|
||||
parser.NextToken()
|
||||
else
|
||||
parser.errors+=new/scriptError/InvalidID(parser.curToken)
|
||||
return KW_ERR
|
||||
if(!parser.CheckToken(")", /token/symbol))
|
||||
return KW_FAIL
|
||||
/datum/n_Keyword/nS_Keyword/kwElse/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
var/list/L = parser.curBlock.statements
|
||||
var/datum/node/statement/IfStatement/stmt
|
||||
|
||||
if(istype(parser.curToken, /token/end)) //Function prototype
|
||||
parser.curBlock.statements+=def
|
||||
else if(parser.curToken.value=="{" && istype(parser.curToken, /token/symbol))
|
||||
def.block = new
|
||||
parser.curBlock.statements+=def
|
||||
parser.curBlock.functions[def.func_name]=def
|
||||
parser.AddBlock(def.block)
|
||||
if(L && L.len)
|
||||
stmt = L[L.len] //Get the last statement in the current block
|
||||
|
||||
if(!stmt || !istype(stmt) || stmt.else_block) //Ensure that it is an if statement
|
||||
usr << "NTSL: ELSE IF FAILED: [!stmt], [!istype(stmt)], [!istype(stmt) || stmt.else_block]" // Usr is unsafe as SHIT but JUST incase I forget this debug line like the fucking asset cache...
|
||||
parser.errors += new/datum/scriptError/ExpectedToken("if statement", parser.curToken)
|
||||
return KW_FAIL
|
||||
|
||||
parser.NextToken() //skip 'else' token
|
||||
if(!parser.CheckToken("{", /datum/token/symbol, skip = 0))
|
||||
return KW_ERR
|
||||
|
||||
stmt.else_block = new()
|
||||
parser.AddBlock(stmt.else_block)
|
||||
|
||||
/datum/n_Keyword/nS_Keyword/kwWhile/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
var/datum/node/statement/WhileLoop/stmt = new
|
||||
parser.NextToken() //skip 'while' token
|
||||
stmt.cond = parser.ParseParenExpression()
|
||||
if(!parser.CheckToken(")", /datum/token/symbol))
|
||||
return KW_FAIL
|
||||
|
||||
if(!parser.CheckToken("{", /datum/token/symbol, skip=0))
|
||||
return KW_ERR
|
||||
|
||||
parser.curBlock.statements += stmt
|
||||
stmt.block = new
|
||||
parser.AddBlock(stmt.block)
|
||||
|
||||
/datum/n_Keyword/nS_Keyword/kwBreak/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
if(istype(parser.curBlock, /datum/node/BlockDefinition/GlobalBlock))
|
||||
parser.errors += new/datum/scriptError/BadToken(parser.curToken)
|
||||
. = KW_WARN
|
||||
|
||||
var/datum/node/statement/BreakStatement/stmt = new
|
||||
parser.NextToken() //skip 'break' token
|
||||
parser.curBlock.statements += stmt
|
||||
|
||||
/datum/n_Keyword/nS_Keyword/kwContinue/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
if(istype(parser.curBlock, /datum/node/BlockDefinition/GlobalBlock))
|
||||
parser.errors += new/datum/scriptError/BadToken(parser.curToken)
|
||||
. = KW_WARN
|
||||
|
||||
var/datum/node/statement/ContinueStatement/stmt = new
|
||||
parser.NextToken() //skip 'break' token
|
||||
parser.curBlock.statements += stmt
|
||||
|
||||
/datum/n_Keyword/nS_Keyword/kwDef/Parse(var/datum/n_Parser/nS_Parser/parser)
|
||||
. = KW_PASS
|
||||
var/datum/node/statement/FunctionDefinition/def = new
|
||||
parser.NextToken() //skip 'def' token
|
||||
|
||||
if(!parser.options.IsValidID(parser.curToken.value))
|
||||
parser.errors += new/datum/scriptError/InvalidID(parser.curToken)
|
||||
return KW_FAIL
|
||||
|
||||
def.func_name = parser.curToken.value
|
||||
parser.NextToken()
|
||||
|
||||
if(!parser.CheckToken("(", /datum/token/symbol))
|
||||
return KW_FAIL
|
||||
|
||||
for() //for now parameters can be separated by whitespace - they don't need a comma in between
|
||||
if(istype(parser.curToken, /datum/token/symbol))
|
||||
switch(parser.curToken.value)
|
||||
if(",")
|
||||
parser.NextToken()
|
||||
if(")")
|
||||
break
|
||||
else
|
||||
parser.errors+=new/scriptError/BadToken(parser.curToken)
|
||||
return KW_FAIL
|
||||
parser.errors += new/datum/scriptError/BadToken(parser.curToken)
|
||||
return KW_ERR
|
||||
|
||||
else if(istype(parser.curToken, /datum/token/word))
|
||||
def.parameters += parser.curToken.value
|
||||
parser.NextToken()
|
||||
|
||||
else
|
||||
parser.errors += new/datum/scriptError/InvalidID(parser.curToken)
|
||||
return KW_ERR
|
||||
|
||||
if(!parser.CheckToken(")", /datum/token/symbol))
|
||||
return KW_FAIL
|
||||
|
||||
if(istype(parser.curToken, /datum/token/end)) //Function prototype
|
||||
parser.curBlock.statements += def
|
||||
|
||||
else if(parser.curToken.value == "{" && istype(parser.curToken, /datum/token/symbol))
|
||||
def.block = new
|
||||
parser.curBlock.statements += def
|
||||
parser.curBlock.functions[def.func_name] = def
|
||||
parser.AddBlock(def.block)
|
||||
else
|
||||
parser.errors += new/datum/scriptError/BadToken(parser.curToken)
|
||||
return KW_FAIL
|
||||
|
||||
@@ -5,19 +5,17 @@
|
||||
Class: n_Parser
|
||||
An object that reads tokens and produces an AST (abstract syntax tree).
|
||||
*/
|
||||
/n_Parser
|
||||
var
|
||||
/datum/n_Parser
|
||||
/*
|
||||
Var: index
|
||||
The parser's current position in the token's list.
|
||||
*/
|
||||
index = 1
|
||||
list
|
||||
var/index = 1
|
||||
/*
|
||||
Var: tokens
|
||||
A list of tokens in the source code generated by a scanner.
|
||||
*/
|
||||
tokens = new
|
||||
var/list/tokens = new
|
||||
/*
|
||||
Var: errors
|
||||
A list of fatal errors found by the parser. If there are any items in this list, then it is not safe to run the returned AST.
|
||||
@@ -25,48 +23,44 @@
|
||||
See Also:
|
||||
- <scriptError>
|
||||
*/
|
||||
errors = new
|
||||
var/list/errors = new
|
||||
/*
|
||||
Var: warnings
|
||||
A list of non-fatal problems in the script.
|
||||
*/
|
||||
warnings = new
|
||||
token
|
||||
var/list/warnings = new
|
||||
/*
|
||||
Var: curToken
|
||||
The token at <index> in <tokens>.
|
||||
*/
|
||||
curToken
|
||||
stack
|
||||
blocks=new
|
||||
node/BlockDefinition
|
||||
GlobalBlock/global_block=new
|
||||
curBlock
|
||||
var/datum/token/curToken
|
||||
var/datum/stack/blocks = new
|
||||
var/datum/node/BlockDefinition/GlobalBlock/global_block = new
|
||||
var/datum/node/BlockDefinition/GlobalBlock/curBlock
|
||||
|
||||
proc
|
||||
/*
|
||||
Proc: Parse
|
||||
Reads the tokens and returns the AST's <GlobalBlock> node. Be sure to populate the tokens list before calling this procedure.
|
||||
*/
|
||||
Parse()
|
||||
|
||||
/datum/n_Parser/proc/Parse()
|
||||
return
|
||||
/*
|
||||
Proc: NextToken
|
||||
Sets <curToken> to the next token in the <tokens> list, or null if there are no more tokens.
|
||||
*/
|
||||
NextToken()
|
||||
if(index>=tokens.len)
|
||||
curToken=null
|
||||
else
|
||||
curToken=tokens[++index]
|
||||
return curToken
|
||||
/datum/n_Parser/proc/NextToken()
|
||||
if(index >= tokens.len)
|
||||
curToken = null
|
||||
else
|
||||
curToken = tokens[++index]
|
||||
return curToken
|
||||
|
||||
/*
|
||||
Class: nS_Parser
|
||||
An implmentation of a parser for n_Script.
|
||||
*/
|
||||
/n_Parser/nS_Parser
|
||||
var/n_scriptOptions/nS_Options/options
|
||||
/datum/n_Parser/nS_Parser
|
||||
var/datum/n_scriptOptions/nS_Options/options
|
||||
/*
|
||||
Constructor: New
|
||||
|
||||
@@ -74,117 +68,138 @@
|
||||
tokens - A list of tokens to parse.
|
||||
options - An object used for configuration.
|
||||
*/
|
||||
New(tokens[], n_scriptOptions/options)
|
||||
src.tokens=tokens
|
||||
src.options=options
|
||||
curBlock=global_block
|
||||
return ..()
|
||||
/datum/n_Parser/nS_Parser/New(tokens[], var/datum/n_scriptOptions/options)
|
||||
src.tokens = tokens
|
||||
src.options = options
|
||||
curBlock = global_block
|
||||
return ..()
|
||||
|
||||
Parse()
|
||||
ASSERT(tokens)
|
||||
for(,src.index<=src.tokens.len, src.index++)
|
||||
curToken=tokens[index]
|
||||
switch(curToken.type)
|
||||
if(/token/keyword)
|
||||
var/n_Keyword/kw=options.keywords[curToken.value]
|
||||
kw=new kw()
|
||||
if(kw)
|
||||
if(!kw.Parse(src))
|
||||
return
|
||||
if(/token/word)
|
||||
var/token/ntok
|
||||
if(index+1>tokens.len)
|
||||
errors+=new/scriptError/BadToken(curToken)
|
||||
continue
|
||||
ntok=tokens[index+1]
|
||||
if(!istype(ntok, /token/symbol))
|
||||
errors+=new/scriptError/BadToken(ntok)
|
||||
continue
|
||||
if(ntok.value=="(")
|
||||
ParseFunctionStatement()
|
||||
else if(options.assign_operators.Find(ntok.value))
|
||||
ParseAssignment()
|
||||
else
|
||||
errors+=new/scriptError/BadToken(ntok)
|
||||
continue
|
||||
if(!istype(curToken, /token/end))
|
||||
errors+=new/scriptError/ExpectedToken(";", curToken)
|
||||
continue
|
||||
if(/token/symbol)
|
||||
if(curToken.value=="}")
|
||||
if(!EndBlock())
|
||||
errors+=new/scriptError/BadToken(curToken)
|
||||
continue
|
||||
else
|
||||
errors+=new/scriptError/BadToken(curToken)
|
||||
continue
|
||||
if(/token/end)
|
||||
warnings+=new/scriptError/BadToken(curToken)
|
||||
/datum/n_Parser/nS_Parser/Parse()
|
||||
ASSERT(tokens)
|
||||
for(,src.index <= src.tokens.len, src.index++)
|
||||
curToken = tokens[index]
|
||||
switch(curToken.type)
|
||||
if(/datum/token/keyword)
|
||||
var/datum/n_Keyword/kw = options.keywords[curToken.value]
|
||||
kw = new kw()
|
||||
if(kw)
|
||||
if(!kw.Parse(src))
|
||||
return
|
||||
|
||||
if(/datum/token/word)
|
||||
var/datum/token/ntok
|
||||
if(index + 1 > tokens.len)
|
||||
errors += new/datum/scriptError/BadToken(curToken)
|
||||
continue
|
||||
|
||||
ntok = tokens[index + 1]
|
||||
|
||||
if(!istype(ntok, /datum/token/symbol))
|
||||
errors += new/datum/scriptError/BadToken(ntok)
|
||||
continue
|
||||
|
||||
if(ntok.value == "(")
|
||||
ParseFunctionStatement()
|
||||
|
||||
else if(options.assign_operators.Find(ntok.value))
|
||||
ParseAssignment()
|
||||
|
||||
else
|
||||
errors+=new/scriptError/BadToken(curToken)
|
||||
return
|
||||
return global_block
|
||||
errors += new/datum/scriptError/BadToken(ntok)
|
||||
continue
|
||||
|
||||
proc
|
||||
CheckToken(val, type, err=1, skip=1)
|
||||
if(curToken.value!=val || !istype(curToken,type))
|
||||
if(err)
|
||||
errors+=new/scriptError/ExpectedToken(val, curToken)
|
||||
return 0
|
||||
if(skip)NextToken()
|
||||
return 1
|
||||
if(!istype(curToken, /datum/token/end))
|
||||
errors += new/datum/scriptError/ExpectedToken(";", curToken)
|
||||
continue
|
||||
|
||||
AddBlock(node/BlockDefinition/B)
|
||||
blocks.Push(curBlock)
|
||||
curBlock=B
|
||||
if(/datum/token/symbol)
|
||||
if(curToken.value == "}")
|
||||
if(!EndBlock())
|
||||
errors += new/datum/scriptError/BadToken(curToken)
|
||||
continue
|
||||
|
||||
EndBlock()
|
||||
if(curBlock==global_block) return 0
|
||||
curBlock=blocks.Pop()
|
||||
return 1
|
||||
else
|
||||
errors += new/datum/scriptError/BadToken(curToken)
|
||||
continue
|
||||
|
||||
if(/datum/token/end)
|
||||
warnings += new/datum/scriptError/BadToken(curToken)
|
||||
continue
|
||||
|
||||
ParseAssignment()
|
||||
var/name=curToken.value
|
||||
if(!options.IsValidID(name))
|
||||
errors+=new/scriptError/InvalidID(curToken)
|
||||
return
|
||||
NextToken()
|
||||
var/t=options.binary_operators[options.assign_operators[curToken.value]]
|
||||
var/node/statement/VariableAssignment/stmt=new()
|
||||
stmt.var_name=new(name)
|
||||
NextToken()
|
||||
if(t)
|
||||
stmt.value=new t()
|
||||
stmt.value:exp=new/node/expression/value/variable(stmt.var_name)
|
||||
stmt.value:exp2=ParseExpression()
|
||||
else
|
||||
stmt.value=ParseExpression()
|
||||
curBlock.statements+=stmt
|
||||
|
||||
ParseFunctionStatement()
|
||||
if(!istype(curToken, /token/word))
|
||||
errors+=new/scriptError("Bad identifier in function call.")
|
||||
errors += new/datum/scriptError/BadToken(curToken)
|
||||
return
|
||||
var/node/statement/FunctionCall/stmt=new
|
||||
stmt.func_name=curToken.value
|
||||
NextToken() //skip function name
|
||||
if(!CheckToken("(", /token/symbol)) //Check for and skip open parenthesis
|
||||
return
|
||||
var/loops = 0
|
||||
for()
|
||||
loops++
|
||||
if(loops>=800)
|
||||
errors +=new/scriptError("Cannot find ending params.")
|
||||
return
|
||||
|
||||
if(!curToken)
|
||||
errors+=new/scriptError/EndOfFile()
|
||||
return
|
||||
if(istype(curToken, /token/symbol) && curToken.value==")")
|
||||
curBlock.statements+=stmt
|
||||
NextToken() //Skip close parenthesis
|
||||
return
|
||||
var/node/expression/P=ParseParamExpression(check_functions = 1)
|
||||
stmt.parameters+=P
|
||||
if(istype(curToken, /token/symbol) && curToken.value==",") NextToken()
|
||||
return global_block
|
||||
|
||||
/datum/n_Parser/nS_Parser/proc/CheckToken(val, type, err = 1, skip = 1)
|
||||
if(curToken.value != val || !istype(curToken, type))
|
||||
if(err)
|
||||
errors += new/datum/scriptError/ExpectedToken(val, curToken)
|
||||
return 0
|
||||
if(skip)
|
||||
NextToken()
|
||||
|
||||
return 1
|
||||
|
||||
/datum/n_Parser/nS_Parser/proc/AddBlock(var/datum/node/BlockDefinition/B)
|
||||
blocks.Push(curBlock)
|
||||
curBlock = B
|
||||
|
||||
/datum/n_Parser/nS_Parser/proc/EndBlock()
|
||||
if(curBlock == global_block)
|
||||
return 0
|
||||
|
||||
curBlock = blocks.Pop()
|
||||
return 1
|
||||
|
||||
/datum/n_Parser/nS_Parser/proc/ParseAssignment()
|
||||
var/name = curToken.value
|
||||
if(!options.IsValidID(name))
|
||||
errors += new/datum/scriptError/InvalidID(curToken)
|
||||
return
|
||||
|
||||
NextToken()
|
||||
var/t = options.binary_operators[options.assign_operators[curToken.value]]
|
||||
var/datum/node/statement/VariableAssignment/stmt = new()
|
||||
stmt.var_name = new(name)
|
||||
NextToken()
|
||||
|
||||
if(t)
|
||||
stmt.value = new t()
|
||||
stmt.value:exp = new/datum/node/expression/value/variable(stmt.var_name)
|
||||
stmt.value:exp2 = ParseExpression()
|
||||
else
|
||||
stmt.value = ParseExpression()
|
||||
|
||||
curBlock.statements += stmt
|
||||
|
||||
/datum/n_Parser/nS_Parser/proc/ParseFunctionStatement()
|
||||
if(!istype(curToken, /datum/token/word))
|
||||
errors += new/datum/scriptError("Bad identifier in function call.")
|
||||
return
|
||||
|
||||
var/datum/node/statement/FunctionCall/stmt=new
|
||||
stmt.func_name = curToken.value
|
||||
NextToken() //skip function name
|
||||
if(!CheckToken("(", /datum/token/symbol)) //Check for and skip open parenthesis
|
||||
return
|
||||
var/loops = 0
|
||||
for()
|
||||
loops++
|
||||
if(loops >= 800)
|
||||
errors +=new/datum/scriptError("Cannot find ending params.")
|
||||
return
|
||||
|
||||
if(!curToken)
|
||||
errors+=new/datum/scriptError/EndOfFile()
|
||||
return
|
||||
if(istype(curToken, /datum/token/symbol) && curToken.value == ")")
|
||||
curBlock.statements += stmt
|
||||
NextToken() //Skip close parenthesis
|
||||
return
|
||||
|
||||
var/datum/node/expression/P = ParseParamExpression(check_functions = 1)
|
||||
stmt.parameters += P
|
||||
if(istype(curToken, /datum/token/symbol) && curToken.value == ",")
|
||||
NextToken()
|
||||
|
||||
Reference in New Issue
Block a user