mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Fixed some indexing bugs
This commit is contained in:
21
README.md
21
README.md
@@ -8,6 +8,15 @@ This is the Toy programming language interpreter, written in C.
|
|||||||
|
|
||||||
Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path.
|
Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path.
|
||||||
|
|
||||||
|
## Nifty Features
|
||||||
|
|
||||||
|
* Simple C-like syntax
|
||||||
|
* Bytecode intermediate compilation
|
||||||
|
* `import` and `export` variables from the host program
|
||||||
|
* Optional, but robust type system
|
||||||
|
* functions and types are first-class citizens
|
||||||
|
* Fancy slice notation for strings, arrays and dictionaries (`print greeting[0:4:-1]; //prints "olleh"`)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Simply run make in the root directory.
|
Simply run make in the root directory.
|
||||||
@@ -15,7 +24,7 @@ Simply run make in the root directory.
|
|||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
```
|
```
|
||||||
import "standard"; //for a bunch of utility functions
|
import standard; //for a bunch of utility functions
|
||||||
|
|
||||||
|
|
||||||
print "Hello world"; //"print" is a keyword
|
print "Hello world"; //"print" is a keyword
|
||||||
@@ -36,13 +45,13 @@ fn makeCounter() { //declare a function like this
|
|||||||
return counter; //closures are explicitly supported
|
return counter; //closures are explicitly supported
|
||||||
}
|
}
|
||||||
|
|
||||||
var counter = makeCounter();
|
var tally = makeCounter();
|
||||||
|
|
||||||
print counter(); //1
|
print tally(); //1
|
||||||
print counter(); //2
|
print tally(); //2
|
||||||
print counter(); //3
|
print tally(); //3
|
||||||
|
|
||||||
export makeCounter; //export this variable to the host program
|
export tally; //export this variable to the host program
|
||||||
```
|
```
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|||||||
@@ -2,14 +2,24 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
var t: type = astype [int];
|
fn makeCounter() {
|
||||||
var u: type = astype [t];
|
var total: int = 0;
|
||||||
|
|
||||||
var a: u;
|
fn counter(): int {
|
||||||
|
return ++total;
|
||||||
|
}
|
||||||
|
|
||||||
t = astype [float]; //redefnition
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
var b: u;
|
var tally = makeCounter();
|
||||||
|
|
||||||
print typeof a; //<[<int>]>
|
print tally(); //1
|
||||||
print typeof b; //<[<float>]>
|
print tally(); //2
|
||||||
|
print tally(); //3
|
||||||
|
|
||||||
|
export tally;
|
||||||
|
|
||||||
|
//heck yeah!
|
||||||
|
import tally as tally2;
|
||||||
|
print tally2(); //4
|
||||||
|
|||||||
@@ -1,8 +1,22 @@
|
|||||||
|
|
||||||
|
//test basic indexing
|
||||||
|
{
|
||||||
|
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
||||||
|
|
||||||
|
assert week[1] == "tuesday", "basic indexing failed (single element)";
|
||||||
|
|
||||||
|
assert week[1:1] == ["tuesday"], "basic indexing failed (single element as array)";
|
||||||
|
|
||||||
|
assert week[:] == ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], "basic default indexing failed (first and second)";
|
||||||
|
assert week[::] == ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], "basic default indexing failed (first, second and third)";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//test basic replacement
|
//test basic replacement
|
||||||
{
|
{
|
||||||
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
var week = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
||||||
|
|
||||||
week[3] = "Holiday";
|
week[3:3] = "Holiday";
|
||||||
|
|
||||||
assert week == ["monday", "tuesday", "wednesday", "Holiday", "friday", "saturday", "sunday"], "basic replacement failed";
|
assert week == ["monday", "tuesday", "wednesday", "Holiday", "friday", "saturday", "sunday"], "basic replacement failed";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
//test basic replacement
|
//test basic indexing
|
||||||
var greeting: string = "hello world";
|
var greeting: string = "hello world";
|
||||||
|
|
||||||
|
assert greeting[1] == "e", "basic default index failed (first)";
|
||||||
|
|
||||||
|
assert greeting[:] == "hello world", "basic default index failed (first and second)";
|
||||||
|
|
||||||
|
assert greeting[::] == "hello world", "basic default index failed (first, second & third)";
|
||||||
|
|
||||||
|
assert greeting[0:4] == "hello", "basic indexing failed";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//test basic replacement
|
||||||
greeting[0:4] = "goodnight";
|
greeting[0:4] = "goodnight";
|
||||||
|
|
||||||
assert greeting == "goodnight world", "basic replacement failed";
|
assert greeting == "goodnight world", "basic replacement failed";
|
||||||
|
|
||||||
|
|
||||||
//test backwards string
|
//test backwards string
|
||||||
assert greeting[::-1] == "dlrow thgindoog", "backwards string failed";
|
assert greeting[::-1] == "dlrow thgindoog", "backwards string failed";
|
||||||
|
assert greeting[11:15:-1] == "dlrow", "backwards indexed string failed";
|
||||||
|
|
||||||
|
|
||||||
//test string weird manipulation
|
//test string weird manipulation
|
||||||
|
|||||||
@@ -1386,7 +1386,7 @@ static bool execIndex(Interpreter* interpreter) {
|
|||||||
freeLiteral(second);
|
freeLiteral(second);
|
||||||
freeLiteral(first);
|
freeLiteral(first);
|
||||||
freeLiteral(compound);
|
freeLiteral(compound);
|
||||||
freeLiteral(idn);
|
//freeLiteral(idn); //since compound is freed, idn is still pointing there
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
if (!IS_NULL(second)) {
|
if (!IS_NULL(second)) {
|
||||||
if (IS_BOOLEAN(second)) {
|
if (IS_BOOLEAN(second)) {
|
||||||
freeLiteral(second);
|
freeLiteral(second);
|
||||||
second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count);
|
second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,10 +387,10 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
LiteralArray* result = ALLOCATE(LiteralArray, 1);
|
LiteralArray* result = ALLOCATE(LiteralArray, 1);
|
||||||
initLiteralArray(result);
|
initLiteralArray(result);
|
||||||
|
|
||||||
int min = AS_INTEGER(third) > 0 ? 0 : AS_INTEGER(second) - 1;
|
int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second);
|
||||||
|
|
||||||
//copy compound into result
|
//copy compound into result
|
||||||
for (int i = min; i >= 0 && i <= AS_ARRAY(compound)->count && i >= AS_INTEGER(first) && i < AS_INTEGER(second); i += AS_INTEGER(third)) {
|
for (int i = min; i >= 0 && i <= AS_ARRAY(compound)->count && i >= AS_INTEGER(first) && i <= AS_INTEGER(second); i += AS_INTEGER(third)) {
|
||||||
Literal idx = TO_INTEGER_LITERAL(i);
|
Literal idx = TO_INTEGER_LITERAL(i);
|
||||||
Literal tmp = getLiteralArray(AS_ARRAY(compound), idx);
|
Literal tmp = getLiteralArray(AS_ARRAY(compound), idx);
|
||||||
pushLiteralArray(result, tmp);
|
pushLiteralArray(result, tmp);
|
||||||
@@ -417,7 +417,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
if (!IS_NULL(second)) {
|
if (!IS_NULL(second)) {
|
||||||
if (IS_BOOLEAN(second)) {
|
if (IS_BOOLEAN(second)) {
|
||||||
freeLiteral(second);
|
freeLiteral(second);
|
||||||
second = TO_INTEGER_LITERAL(AS_ARRAY(compound)->count);
|
second = TO_INTEGER_LITERAL(AS_INTEGER(first));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,6 +487,7 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
|
|
||||||
int min = AS_INTEGER(third) > 0 ? 0 : AS_ARRAY(assign)->count - 1;
|
int min = AS_INTEGER(third) > 0 ? 0 : AS_ARRAY(assign)->count - 1;
|
||||||
|
|
||||||
|
if (IS_ARRAY(assign)) { //push elements of an assigned array
|
||||||
for (int i = min; i >= 0 && i < AS_ARRAY(assign)->count; i += AS_INTEGER(third)) {
|
for (int i = min; i >= 0 && i < AS_ARRAY(assign)->count; i += AS_INTEGER(third)) {
|
||||||
Literal idx = TO_INTEGER_LITERAL(i);
|
Literal idx = TO_INTEGER_LITERAL(i);
|
||||||
Literal tmp = getLiteralArray(AS_ARRAY(assign), idx); //backwards
|
Literal tmp = getLiteralArray(AS_ARRAY(assign), idx); //backwards
|
||||||
@@ -497,6 +498,10 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
freeLiteral(idx);
|
freeLiteral(idx);
|
||||||
freeLiteral(tmp);
|
freeLiteral(tmp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else { //push just one element into the array
|
||||||
|
pushLiteralArray(result, assign);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = AS_INTEGER(second) + 1; i < AS_ARRAY(compound)->count; i++) {
|
for (int i = AS_INTEGER(second) + 1; i < AS_ARRAY(compound)->count; i++) {
|
||||||
Literal idx = TO_INTEGER_LITERAL(i);
|
Literal idx = TO_INTEGER_LITERAL(i);
|
||||||
@@ -649,11 +654,12 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
//start building a new string from the old one
|
//start building a new string from the old one
|
||||||
char* result = ALLOCATE(char, MAX_STRING_LENGTH);
|
char* result = ALLOCATE(char, MAX_STRING_LENGTH);
|
||||||
|
|
||||||
int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second) - 1;
|
int lower = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(first) -1;
|
||||||
|
int min = AS_INTEGER(third) > 0 ? AS_INTEGER(first) : AS_INTEGER(second) -1;
|
||||||
|
|
||||||
//copy compound into result
|
//copy compound into result
|
||||||
int resultIndex = 0;
|
int resultIndex = 0;
|
||||||
for (int i = min; i >= AS_INTEGER(first) && i < AS_INTEGER(second); i += AS_INTEGER(third)) {
|
for (int i = min; i >= lower && i <= AS_INTEGER(second); i += AS_INTEGER(third)) {
|
||||||
result[ resultIndex++ ] = AS_STRING(compound)[ i ];
|
result[ resultIndex++ ] = AS_STRING(compound)[ i ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -736,17 +736,24 @@ static Opcode indexAccess(Parser* parser, Node** nodeHandle) {
|
|||||||
emitNodeLiteral(&second, TO_BOOLEAN_LITERAL(true));
|
emitNodeLiteral(&second, TO_BOOLEAN_LITERAL(true));
|
||||||
emitNodeLiteral(&third, TO_BOOLEAN_LITERAL(true));
|
emitNodeLiteral(&third, TO_BOOLEAN_LITERAL(true));
|
||||||
|
|
||||||
|
bool readFirst = false; //pattern matching is bullcrap
|
||||||
|
|
||||||
//eat the first
|
//eat the first
|
||||||
if (!match(parser, TOKEN_COLON)) {
|
if (!match(parser, TOKEN_COLON)) {
|
||||||
freeNode(first);
|
freeNode(first);
|
||||||
parsePrecedence(parser, &first, PREC_TERNARY);
|
parsePrecedence(parser, &first, PREC_TERNARY);
|
||||||
match(parser, TOKEN_COLON);
|
match(parser, TOKEN_COLON);
|
||||||
|
readFirst = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
if (match(parser, TOKEN_BRACKET_RIGHT)) {
|
||||||
|
|
||||||
|
if (readFirst) {
|
||||||
freeNode(second);
|
freeNode(second);
|
||||||
freeNode(third);
|
|
||||||
second = NULL;
|
second = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeNode(third);
|
||||||
third = NULL;
|
third = NULL;
|
||||||
|
|
||||||
emitNodeIndex(nodeHandle, first, second, third);
|
emitNodeIndex(nodeHandle, first, second, third);
|
||||||
|
|||||||
Reference in New Issue
Block a user