Skip to content

Commit

Permalink
Complete NTSL refactor (#4486)
Browse files Browse the repository at this point in the history
馃啈 monster860
tweak: Assignemts in NTSL are now operators
fix: sleep() in NTSL no longer breaks things horribly
add: Adds for loops to NTSL
add: Adds the "." and "[]" operator to NTSL. You can do "sig.content" or "some_list[3]" now.
add: You can now create associative lists in NTSL using list()
tweak: Signal processing is done in a function called "process_signal" that must be defined by the user - one argument is passed, the signal argument, change properties on it to change the signal.
fix: The stack traces in the runtime errors for NTSL actually contain line numbers now.
tweak: Broadcasting in NTSL is now done by calling broadcast() with an argument of a signal object, which can be created with a signal() function. Remote signalling is done with remote_signal().
fix: You can do mem() in NTSL with the second argument null and it will remove the property
tweak: several global vars in NTSL have been moved to objects. Languages are in the "languages" object, filters are in the "filter_types" object, and channels are in the "channels" object.
/馃啈
  • Loading branch information
monster860 authored and Altoids1 committed Feb 24, 2019
1 parent c53786c commit 7d8281c
Show file tree
Hide file tree
Showing 20 changed files with 1,098 additions and 786 deletions.
1 change: 1 addition & 0 deletions yogstation.dme
Expand Up @@ -3133,6 +3133,7 @@
#include "yogstation\code\modules\scripting\Interpreter\Evaluation.dm"
#include "yogstation\code\modules\scripting\Interpreter\Interaction.dm"
#include "yogstation\code\modules\scripting\Interpreter\Interpreter.dm"
#include "yogstation\code\modules\scripting\Interpreter\Objects.dm"
#include "yogstation\code\modules\scripting\Interpreter\Scope.dm"
#include "yogstation\code\modules\scripting\Parser\Expressions.dm"
#include "yogstation\code\modules\scripting\Parser\Keywords.dm"
Expand Down
5 changes: 3 additions & 2 deletions yogstation/code/game/machinery/telecomms/machines/server.dm
Expand Up @@ -2,7 +2,7 @@

/obj/item/radio/server/can_receive(frequency,levels)
return FALSE // The server's radio isn't for receiving, it's for outputting. For now.

/obj/machinery/telecomms/server
//NTSL-related stuffs
var/datum/TCS_Compiler/Compiler // the compiler that compiles and runs the code
Expand All @@ -11,8 +11,9 @@
var/rawcode = "" // the code to compile (raw-ass text)
var/obj/item/radio/server/server_radio // Allows the server to talk on the radio, via broadcast() in NTSL
var/last_signal = 0 // Marks the last time an NTSL script called signal() from this server, to stop spam.
var/list/compile_warnings = list()
//End-NTSL

//NTSL-related procs
/obj/machinery/telecomms/server/Initialize()
Compiler = new()
Expand Down
50 changes: 40 additions & 10 deletions yogstation/code/modules/scripting/AST/AST Nodes.dm
Expand Up @@ -16,7 +16,7 @@
/*
Macros: Operator Precedence
The higher the value, the lower the priority in the precedence.
OOP_OR - Logical or
OOP_AND - Logical and
OOP_BIT - Bitwise operations
Expand All @@ -28,6 +28,7 @@
OOP_UNARY - Unary Operators
OOP_GROUP - Parentheses
*/
#define OOP_ASSIGN 0
#define OOP_OR 1 //||
#define OOP_AND 2 //&&
#define OOP_BIT 3 //&, |
Expand All @@ -43,6 +44,7 @@
Class: node
*/
/node
var/token/token // for line number informatino
proc
ToString()
return "[src.type]"
Expand All @@ -53,9 +55,10 @@
var
id_name

New(id)
New(id, token)
.=..()
src.id_name=id
src.token = token

ToString()
return id_name
Expand All @@ -75,22 +78,40 @@
name
precedence

New()
New(token, exp)
.=..()
if(!src.name) src.name="[src.type]"
src.token = token
src.exp = exp

ToString()
return "operator: [name]"

/node/expression/member
var/node/expression/object
var/tmp/temp_object // so you can pre-eval it, used for function calls and assignments
New(token)
src.token = token
return ..()

/node/expression/member/dot
var/node/identifier/id

/node/expression/member/brackets
var/node/expression/index
var/tmp/temp_index


/*
Class: FunctionCall
*/
/node/expression/FunctionCall
//Function calls can also be expressions or statements.
var
func_name
node/identifier/object
list/parameters=new
var/node/expression/function
var/list/parameters=list()
New(token)
.=..()
src.token = token

/*
Class: literal
Expand All @@ -117,24 +138,33 @@
id


New(ident)
New(ident, token)
.=..()
src.token = token
id=ident
if(istext(id))id=new(id)

ToString()
return src.id.ToString()

/node/expression/value/list_init
var/list/init_list

New(token)
. = ..()
src.token = token

/*
Class: reference
*/
/node/expression/value/reference
var
datum/value

New(value)
New(value, token)
.=..()
src.token = token
src.value=value

ToString()
return "ref: [src.value] ([src.value.type])"
return "ref: [src.value] ([src.value.type])"
Expand Up @@ -172,3 +172,15 @@
//
Modulo
precedence=OOP_MULTIPLY

Assign
precedence=OOP_ASSIGN
BitwiseAnd
BitwiseOr
BitwiseXor
Add
Subtract
Multiply
Divide
Power
Modulo
Expand Up @@ -45,7 +45,3 @@
//
group
precedence=OOP_GROUP

New(node/expression/exp)
src.exp=exp
return ..()
15 changes: 4 additions & 11 deletions yogstation/code/modules/scripting/AST/Statements.dm
Expand Up @@ -6,16 +6,9 @@
An object representing a single instruction run by an interpreter.
*/
/node/statement
/*
Class: FunctionCall
Represents a call to a function.
*/
//
FunctionCall
var
func_name
node/identifier/object
list/parameters=new
New(token)
.=..()
src.token=token

/*
Class: FunctionDefinition
Expand Down Expand Up @@ -123,4 +116,4 @@
//
ReturnStatement
var
node/expression/value
node/expression/value
51 changes: 44 additions & 7 deletions yogstation/code/modules/scripting/Errors.dm
Expand Up @@ -69,6 +69,12 @@
line = t.line
message = "[line]: [message]"

InvalidAssignment
message="Left side of assignment cannot be assigned to."

OutdatedScript
message = "Your script looks like it was for an older version of NTSL! Your script may not work as intended. See documentation for new syntax and API."

/*
Class: runtimeError
An error thrown by the interpreter in running the script.
Expand All @@ -81,7 +87,8 @@
A basic description as to what went wrong.
*/
message
stack/stack
scope/scope
token/token

proc
/*
Expand All @@ -90,11 +97,27 @@
*/
ToString()
. = "[name]: [message]"
if(!stack.Top()) return
.+="\nStack:"
while(stack.Top())
var/node/statement/FunctionCall/stmt=stack.Pop()
. += "\n\t [stmt.func_name]()"
if(!scope) return
var/last_line
var/last_col
if(token)
last_line = token.line
last_col = token.column
var/scope/cur_scope = scope
while(cur_scope)
if(cur_scope.function)
. += "\n\tat [cur_scope.function.func_name]([last_line]:[last_col])"
if(cur_scope.call_node && cur_scope.call_node.token)
last_line = cur_scope.call_node.token.line
last_col = cur_scope.call_node.token.column
else
last_line = null
last_col = null
cur_scope = cur_scope.parent
if(last_line)
. += "\n\tat \[global]([last_line]:[last_col])"
else
. += "\n\tat \[internal]"

TypeMismatch
name="TypeMismatchError"
Expand All @@ -111,13 +134,19 @@

UnknownInstruction
name="UnknownInstructionError"
message="Unknown instruction type. This may be due to incompatible compiler and interpreter versions or a lack of implementation."
New(node/op)
message="Unknown instruction type '[op.type]'. This may be due to incompatible compiler and interpreter versions or a lack of implementation."

UndefinedVariable
name="UndefinedVariableError"
New(variable)
message="Variable '[variable]' has not been declared."

IndexOutOfRange
name="IndexOutOfRangeError"
New(obj, idx)
message="Index [obj]\[[idx]] is out of range."

UndefinedFunction
name="UndefinedFunctionError"
New(function)
Expand All @@ -140,7 +169,15 @@
name="DivideByZeroError"
message="Division by zero (or a NULL value) attempted."

InvalidAssignment
message="Left side of assignment cannot be assigned to."

MaxCPU
name="MaxComputationalUse"
New(maxcycles)
message="Maximum amount of computational cycles reached (>= [maxcycles])."

Internal
name="InternalError"
New(exception/E)
message = E.name
12 changes: 12 additions & 0 deletions yogstation/code/modules/scripting/IDE.dm
Expand Up @@ -86,6 +86,18 @@
M << output("<font color = blue>TCS compilation successful!</font color>", "tcserror")
M << output("Time of compile: [gameTimestamp("hh:mm:ss")]","tcserror")
M << output("(0 errors)", "tcserror")
if(Server.compile_warnings.len)
src << output("<b>Compile Warnings</b>", "tcserror")
for(var/scriptError/e in Server.compile_warnings)
src << output("<font color = yellow>\t>[e.message]</font color>", "tcserror")
src << output("([Server.compile_warnings.len] warnings)", "tcserror")
for(var/fuck_you_for_making_me_do_this_altoids in Machine.viewingcode)
var/mob/M = fuck_you_for_making_me_do_this_altoids
if(M.client)
M << output("<b>Compile Warnings</b>", "tcserror")
for(var/scriptError/e in Server.compile_warnings)
M << output("<font color = yellow>\t>[e.message]</font color>", "tcserror")
M << output("([Server.compile_warnings.len] warnings)", "tcserror")

else
src << output(null, "tcserror")
Expand Down

0 comments on commit 7d8281c

Please sign in to comment.