Telecomms Refactor & CodeMirror

This commit does the following:
 - A lot of shit I am really too tired to fucking write about
 - Absolute pathed telecomms scripting
 - Browser Datum traffic control
  - Absolutely lovely replacement for the fucking skin TCS window, using
    codemirror
 - CodeMirror integration for nanoUI
  - Sorta, I didn't work on this as much as I wanted to, because IT TOOK
    11 FUCKING HOURS TO GET THE BROWSER DATUM TO WORK
This commit is contained in:
Tigercat2000
2015-10-28 17:19:18 -07:00
parent f76109ca5c
commit c244a0fe15
38 changed files with 13973 additions and 2155 deletions

View File

@@ -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,89 +203,114 @@
- <ParseParenExpression()>
- <ParseParamExpression()>
*/
ParseExpression(list/end=list(/token/end), list/ErrChars=list("{", "}"))
var/stack
opr=new
val=new
src.expecting=VALUE
for()
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(index>tokens.len) //End of File
errors+=new/scriptError/EndOfFile()
break
var/token/ntok
if(index+1<=tokens.len)
ntok=tokens[index+1]
if(EndOfExpression(end))
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())
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
if(istype(curToken, /datum/token/symbol) && ErrChars.Find(curToken.value))
errors += new/datum/scriptError/BadToken(curToken)
break
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, /token/symbol)\
&& istype(curToken, /token/word)) //Parse function call
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 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)
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
else
if(expecting!=VALUE)
errors+=new/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/node/N=val.Pop()
errors+=new/scriptError("Error parsing expression. Unexpected value left on stack: [N.ToString()].")
return null
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
@@ -271,25 +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>=1000)
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(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
@@ -298,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
@@ -310,5 +366,6 @@
See Also:
- <ParseExpression()>
*/
ParseParamExpression()
return ParseExpression(list(",", ")"))
/datum/n_Parser/nS_Parser/proc/ParseParamExpression(var/check_functions = 0)
var/cf = check_functions
return ParseExpression(list(",", ")"), check_functions = cf)