signalscript
signalscript copied to clipboard
A small interpreted scripting language with C-style Syntax. Written in C++.
signalscript
This is a fork of a scripting language that an old friend of mine made back in 2010.
The project got abandoned, and I made this fork just to get familiar with the code, add some small features, and learn about abstract syntax trees.
What the language had when Jeremic dropped the project:
- Fully working expressions.
- Conditional if/else blocks.
- Functions.
- All binary operators except modulo, exponent, +=, and -=.
- All unary operators except ++ and --.
- Class parsing but no actual functionality.
- Loop (while and for) parsing but no actual functionality.
- Parsing of break and continue statements but no actual functionality.
- Print() native function but no c-function exports.
- Basic string, number, boolean, and nil types.
What I've added in this fork:
- Loop functionality (compilation and interpretation) for both while and for loops.
- Functionality (compilation and interpretation) for both break and continue statements.
- Class instance creation (via new operator).
- Instance-level scoping for classes.
- Member function calls for classes (parameters are acting up, though).
- Unary operators ++ and -- (postfix).
- String unescaping to support characters such as "\n" and "\t".
- Many bug fixes with error reporting (std::strings were being passed into printf() as opposed to their .c_str() member calls).
- Some changes to the overall structure of the architecture and virtual processor.
- C++ function exporting
- Switch statements (lexing, parsing, compilation, and interpretation).
- Function keyword.
- Improvements to many binary operators.
- Numeric values which allow decimal places.
- Optimizations / cleanups to the VM code.
- Parsing and AST creation for tables (Currently no compilation or interpretation, though).
What I want to add before I inevitably get tired of playing with the language:
- Class members abstract the table interface (like in Lua).
- Fix parameter bugs for class member functions.
- Global variables.
- Remaining binary operators (modulo, exponent, +=, and -=).
Here's what the syntax/usage currently looks like (no class usage here, though, since it's pretty broken):
function testWhile()
{
print("Expect 'haahaahaa'\n ");
n = 0;
while (true)
{
n = n + 1;
print("h");
i = 0;
while (i < 2)
{
i = i + 1;
print("a");
}
if (n == 3)
break;
else
continue;
}
print("\n");
}
function testFor()
{
print("Expect '012345 -- 54321 -- 13579'\n ");
for (i = 0; i <= 5; i = i + 1)
{
print(i);
}
print(" -- ");
for (i = 5; true; i = i - 1)
{
print(i);
if (i == 1)
break;
}
print(" -- ");
for (i = 1; i < 10; i = i + 1)
{
if (i == 2 || i == 4 || i == 6 || i == 8)
continue;
print(i);
}
print("\n");
}
function testIncDec()
{
print("Expect '01021 | -1 | 4'\n ");
var = 0;
print(var);
var++;
print(var);
var--;
print(var);
var++;var++;
print(var);
var--;
print(var);
print(" | ");
var--;var--;
print(var);
print(" | ");
val = 1;
val = val + val++;
print(val);
print("\n");
}
function testSwitch(value)
{
switch (value)
{
case 3:
print("three, ");
case 2:
{
print("two, ");
}
case 1:
{
print("one\n");
break;
}
default:
{
print("other\n");
}
}
}
function main()
{
testWhile();
testFor();
testIncDec();
print("Expect 'one'\n ");
testSwitch(1);
print("Expect 'two, one'\n ");
testSwitch(2);
print("Expect 'three, two, one'\n ");
testSwitch(3);
print("Expect 'other'\n ");
testSwitch(4);
}
Here's the usage from C++:
FileInput file (name);
Lexer lexer (file);
Parser parser (lexer);
std::shared_ptr<AST> ast = parser.parse_program ();
Environment env = Environment ();
Compiler::Compile(env, ast);
Interpreter interpreter(env);
interpreter.execute ();
Here's how you export a C++ function:
//exported function prototype
std::shared_ptr<Object> printFunc(Environment env, std::vector<std::shared_ptr<Object>> args);
//call this before Compiler::Compile(env, ast);
env.exportFunction("print", printFunc);