All the EOLs are now LF.

Fuck you too 0D :^)
This commit is contained in:
PJB3005
2016-01-16 23:28:07 +01:00
parent f2ed22a049
commit 1a2f9ab059
898 changed files with 222641 additions and 222641 deletions

View File

@@ -1,371 +1,371 @@
/*
File: Expressions
Procedures for parsing expressions.
*/
/*
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.
*/
#define OPERATOR 1
#define VALUE 2
#define SHIFT 0
#define REDUCE 1
/*
Class: nS_Parser
*/
/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.
*/
var/expecting = VALUE
/*
Proc: Precedence
Compares two operators, decides which is higher in the order of operations, and returns <SHIFT> or <REDUCE>.
*/
/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.
*/
/datum/n_Parser/nS_Parser/proc/GetExpression(var/datum/token/T)
if(!T)
return
if(istype(T, /datum/node/expression))
return T
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
Gets a path related to a token or string and returns an instance of the given type. This is used to get an instance of either a binary or unary
operator from a token.
Parameters:
O - The input value. If this is a token, O is reset to the token's value.
When O is a string and is in L, its associated value is used as the path to instantiate.
type - The desired type of the returned object.
L - The list in which to search for O.
See Also:
- <GetBinaryOperator()>
- <GetUnaryOperator()>
*/
/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
Uses <GetOperator()> to search for an instance of a binary operator type with which the given string is associated. For example, if
O is set to "+", an <Add> node is returned.
See Also:
- <GetOperator()>
- <GetUnaryOperator()>
*/
/datum/n_Parser/nS_Parser/proc/GetBinaryOperator(O)
return GetOperator(O, /datum/node/expression/operator/binary, options.binary_operators)
/*
Proc: GetUnaryOperator
Uses <GetOperator()> to search for an instance of a unary operator type with which the given string is associated. For example, if
O is set to "!", a <LogicalNot> node is returned.
See Also:
- <GetOperator()>
- <GetBinaryOperator()>
*/
/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.
*/
/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
Returns true if the current token represents the end of an expression.
Parameters:
end - A list of values to compare the current token to.
*/
/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
Uses the Shunting-yard algorithm to parse expressions.
Notes:
- When an opening parenthesis is found, then <ParseParenExpression()> is called to handle it.
- The <expecting> variable helps distinguish unary operators from binary operators (for cases like the - operator, which can be either).
Articles:
- <http://epaperpress.com/oper/>
- <http://en.wikipedia.org/wiki/Shunting-yard_algorithm>
See Also:
- <ParseFunctionExpression()>
- <ParseParenExpression()>
- <ParseParamExpression()>
*/
/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(istype(curToken, /datum/token/symbol) && ErrChars.Find(curToken.value))
errors += new/datum/scriptError/BadToken(curToken)
break
if(index > tokens.len) //End of File
errors += new/datum/scriptError/EndOfFile()
break
var/datum/token/ntok
if(index + 1 <= tokens.len)
ntok = tokens[index + 1]
if(istype(curToken, /datum/token/symbol) && curToken.value == "(") //Parse parentheses expression
if(expecting != VALUE)
errors += new/datum/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
val.Push(ParseParenExpression())
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
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
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
Parses a function call inside of an expression.
See Also:
- <ParseExpression()>
*/
/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
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
Parses an expression that ends with a close parenthesis. This is used for parsing expressions inside of parentheses.
See Also:
- <ParseExpression()>
*/
/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
Parses an expression that ends with either a comma or close parenthesis. This is used for parsing the parameters passed to a function call.
See Also:
- <ParseExpression()>
*/
/datum/n_Parser/nS_Parser/proc/ParseParamExpression(var/check_functions = 0)
var/cf = check_functions
/*
File: Expressions
Procedures for parsing expressions.
*/
/*
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.
*/
#define OPERATOR 1
#define VALUE 2
#define SHIFT 0
#define REDUCE 1
/*
Class: nS_Parser
*/
/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.
*/
var/expecting = VALUE
/*
Proc: Precedence
Compares two operators, decides which is higher in the order of operations, and returns <SHIFT> or <REDUCE>.
*/
/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.
*/
/datum/n_Parser/nS_Parser/proc/GetExpression(var/datum/token/T)
if(!T)
return
if(istype(T, /datum/node/expression))
return T
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
Gets a path related to a token or string and returns an instance of the given type. This is used to get an instance of either a binary or unary
operator from a token.
Parameters:
O - The input value. If this is a token, O is reset to the token's value.
When O is a string and is in L, its associated value is used as the path to instantiate.
type - The desired type of the returned object.
L - The list in which to search for O.
See Also:
- <GetBinaryOperator()>
- <GetUnaryOperator()>
*/
/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
Uses <GetOperator()> to search for an instance of a binary operator type with which the given string is associated. For example, if
O is set to "+", an <Add> node is returned.
See Also:
- <GetOperator()>
- <GetUnaryOperator()>
*/
/datum/n_Parser/nS_Parser/proc/GetBinaryOperator(O)
return GetOperator(O, /datum/node/expression/operator/binary, options.binary_operators)
/*
Proc: GetUnaryOperator
Uses <GetOperator()> to search for an instance of a unary operator type with which the given string is associated. For example, if
O is set to "!", a <LogicalNot> node is returned.
See Also:
- <GetOperator()>
- <GetBinaryOperator()>
*/
/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.
*/
/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
Returns true if the current token represents the end of an expression.
Parameters:
end - A list of values to compare the current token to.
*/
/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
Uses the Shunting-yard algorithm to parse expressions.
Notes:
- When an opening parenthesis is found, then <ParseParenExpression()> is called to handle it.
- The <expecting> variable helps distinguish unary operators from binary operators (for cases like the - operator, which can be either).
Articles:
- <http://epaperpress.com/oper/>
- <http://en.wikipedia.org/wiki/Shunting-yard_algorithm>
See Also:
- <ParseFunctionExpression()>
- <ParseParenExpression()>
- <ParseParamExpression()>
*/
/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(istype(curToken, /datum/token/symbol) && ErrChars.Find(curToken.value))
errors += new/datum/scriptError/BadToken(curToken)
break
if(index > tokens.len) //End of File
errors += new/datum/scriptError/EndOfFile()
break
var/datum/token/ntok
if(index + 1 <= tokens.len)
ntok = tokens[index + 1]
if(istype(curToken, /datum/token/symbol) && curToken.value == "(") //Parse parentheses expression
if(expecting != VALUE)
errors += new/datum/scriptError/ExpectedToken("operator", curToken)
NextToken()
continue
val.Push(ParseParenExpression())
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
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
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
Parses a function call inside of an expression.
See Also:
- <ParseExpression()>
*/
/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
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
Parses an expression that ends with a close parenthesis. This is used for parsing expressions inside of parentheses.
See Also:
- <ParseExpression()>
*/
/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
Parses an expression that ends with either a comma or close parenthesis. This is used for parsing the parameters passed to a function call.
See Also:
- <ParseExpression()>
*/
/datum/n_Parser/nS_Parser/proc/ParseParamExpression(var/check_functions = 0)
var/cf = check_functions
return ParseExpression(list(",", ")"), check_functions = cf)

View File

@@ -1,206 +1,206 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
File: Keywords
*/
var/const/KW_FAIL = 0 //Fatal error; stop parsing entire script.
var/const/KW_PASS = 1 //OK
var/const/KW_ERR = 2 //Non-fatal error, keyword couldn't be handled properly. Ignore keyword but continue on.
var/const/KW_WARN = 3 //Warning
/*
var/const/Class: n_Keyword
var/const/Represents a special statement in the code triggered by a keyword.
*/
/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.
Parameters:
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.
*/
/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
<nS_Options.keywords> list.
Behavior:
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.
*/
/datum/n_Keyword/nS_Keyword/New(var/inline = 0)
if(inline)
qdel (src)
/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
var/datum/node/statement/ReturnStatement/stmt = new
parser.NextToken() //skip 'return' token
stmt.value = parser.ParseExpression()
parser.curBlock.statements += stmt
/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(!parser.CheckToken("{", /datum/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)
/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
if(L && L.len)
ifstmt = L[L.len] //Get the last statement in the current block
if(!ifstmt || !istype(ifstmt) || ifstmt.else_if)
to_chat(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
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
if(!parser.CheckToken("{", /datum/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)
/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(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
to_chat(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/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
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/*
File: Keywords
*/
var/const/KW_FAIL = 0 //Fatal error; stop parsing entire script.
var/const/KW_PASS = 1 //OK
var/const/KW_ERR = 2 //Non-fatal error, keyword couldn't be handled properly. Ignore keyword but continue on.
var/const/KW_WARN = 3 //Warning
/*
var/const/Class: n_Keyword
var/const/Represents a special statement in the code triggered by a keyword.
*/
/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.
Parameters:
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.
*/
/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
<nS_Options.keywords> list.
Behavior:
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.
*/
/datum/n_Keyword/nS_Keyword/New(var/inline = 0)
if(inline)
qdel (src)
/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
var/datum/node/statement/ReturnStatement/stmt = new
parser.NextToken() //skip 'return' token
stmt.value = parser.ParseExpression()
parser.curBlock.statements += stmt
/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(!parser.CheckToken("{", /datum/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)
/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
if(L && L.len)
ifstmt = L[L.len] //Get the last statement in the current block
if(!ifstmt || !istype(ifstmt) || ifstmt.else_if)
to_chat(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
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
if(!parser.CheckToken("{", /datum/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)
/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(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
to_chat(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/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

View File

@@ -1,205 +1,205 @@
/*
File: Parser
*/
/*
Class: n_Parser
An object that reads tokens and produces an AST (abstract syntax tree).
*/
/datum/n_Parser
/*
Var: index
The parser's current position in the token's list.
*/
var/index = 1
/*
Var: tokens
A list of tokens in the source code generated by a scanner.
*/
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.
See Also:
- <scriptError>
*/
var/list/errors = new
/*
Var: warnings
A list of non-fatal problems in the script.
*/
var/list/warnings = new
/*
Var: curToken
The token at <index> in <tokens>.
*/
var/datum/token/curToken
var/datum/stack/blocks = new
var/datum/node/BlockDefinition/GlobalBlock/global_block = new
var/datum/node/BlockDefinition/GlobalBlock/curBlock
/*
Proc: Parse
Reads the tokens and returns the AST's <GlobalBlock> node. Be sure to populate the tokens list before calling this procedure.
*/
/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.
*/
/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.
*/
/datum/n_Parser/nS_Parser
var/datum/n_scriptOptions/nS_Options/options
/*
Constructor: New
Parameters:
tokens - A list of tokens to parse.
options - An object used for configuration.
*/
/datum/n_Parser/nS_Parser/New(tokens[], var/datum/n_scriptOptions/options)
src.tokens = tokens
src.options = options
curBlock = global_block
return ..()
/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/datum/scriptError/BadToken(ntok)
continue
if(!istype(curToken, /datum/token/end))
errors += new/datum/scriptError/ExpectedToken(";", curToken)
continue
if(/datum/token/symbol)
if(curToken.value == "}")
if(!EndBlock())
errors += new/datum/scriptError/BadToken(curToken)
continue
else
errors += new/datum/scriptError/BadToken(curToken)
continue
if(/datum/token/end)
warnings += new/datum/scriptError/BadToken(curToken)
continue
else
errors += new/datum/scriptError/BadToken(curToken)
return
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()
/*
File: Parser
*/
/*
Class: n_Parser
An object that reads tokens and produces an AST (abstract syntax tree).
*/
/datum/n_Parser
/*
Var: index
The parser's current position in the token's list.
*/
var/index = 1
/*
Var: tokens
A list of tokens in the source code generated by a scanner.
*/
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.
See Also:
- <scriptError>
*/
var/list/errors = new
/*
Var: warnings
A list of non-fatal problems in the script.
*/
var/list/warnings = new
/*
Var: curToken
The token at <index> in <tokens>.
*/
var/datum/token/curToken
var/datum/stack/blocks = new
var/datum/node/BlockDefinition/GlobalBlock/global_block = new
var/datum/node/BlockDefinition/GlobalBlock/curBlock
/*
Proc: Parse
Reads the tokens and returns the AST's <GlobalBlock> node. Be sure to populate the tokens list before calling this procedure.
*/
/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.
*/
/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.
*/
/datum/n_Parser/nS_Parser
var/datum/n_scriptOptions/nS_Options/options
/*
Constructor: New
Parameters:
tokens - A list of tokens to parse.
options - An object used for configuration.
*/
/datum/n_Parser/nS_Parser/New(tokens[], var/datum/n_scriptOptions/options)
src.tokens = tokens
src.options = options
curBlock = global_block
return ..()
/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/datum/scriptError/BadToken(ntok)
continue
if(!istype(curToken, /datum/token/end))
errors += new/datum/scriptError/ExpectedToken(";", curToken)
continue
if(/datum/token/symbol)
if(curToken.value == "}")
if(!EndBlock())
errors += new/datum/scriptError/BadToken(curToken)
continue
else
errors += new/datum/scriptError/BadToken(curToken)
continue
if(/datum/token/end)
warnings += new/datum/scriptError/BadToken(curToken)
continue
else
errors += new/datum/scriptError/BadToken(curToken)
return
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()