updated code sample in the readme
This commit is contained in:
@@ -21,25 +21,29 @@ Here's an example of a noja program that orders the items in list using a bubble
|
|||||||
```
|
```
|
||||||
L = [3, 2, 1];
|
L = [3, 2, 1];
|
||||||
|
|
||||||
do {
|
fun swap(a: int, b: int)
|
||||||
swapped = false;
|
return b, a;
|
||||||
|
|
||||||
i = 0;
|
fun order(L: List) {
|
||||||
while i < count(L)-1 and not swapped: {
|
|
||||||
|
|
||||||
if L[i+1] < L[i]: {
|
do {
|
||||||
|
swapped = false;
|
||||||
swapped = true;
|
|
||||||
tmp = L[i+1];
|
i = 0;
|
||||||
L[i+1] = L[i];
|
while i < count(L)-1 and not swapped: {
|
||||||
L[i] = tmp;
|
|
||||||
|
swapped = L[i+1] < L[i];
|
||||||
|
if swapped:
|
||||||
|
L[i], L[i+1] = swap(L[i], L[i+1]);
|
||||||
|
|
||||||
|
i = i+1;
|
||||||
}
|
}
|
||||||
|
} while swapped;
|
||||||
i = i + 1;
|
}
|
||||||
}
|
|
||||||
} while swapped;
|
|
||||||
|
|
||||||
print(L, '\n'); # Outputs [1, 2, 3]
|
print(L, '\n'); # [3, 2, 1]
|
||||||
|
order(L);
|
||||||
|
print(L, '\n'); # [1, 2, 3]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Implementation Overview
|
## Implementation Overview
|
||||||
|
|||||||
+15
-12
@@ -1,21 +1,21 @@
|
|||||||
|
|
||||||
fun isSpace(c)
|
fun isSpace(c: String)
|
||||||
return c == " " or c == "\t" or c == "\n";
|
return c == " " or c == "\t" or c == "\n";
|
||||||
|
|
||||||
fun isDigit(c) {
|
fun isDigit(c: String) {
|
||||||
u = unicode(c);
|
u = unicode(c);
|
||||||
d = u - unicode("0");
|
d = u - unicode("0");
|
||||||
return d >= 0 and d <= 9;
|
return d >= 0 and d <= 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun skipSpaces(context) {
|
fun skipSpaces(context: Map) {
|
||||||
# Skip zero or more whitespace characters.
|
# Skip zero or more whitespace characters.
|
||||||
while context.cur < count(context.str)
|
while context.cur < count(context.str)
|
||||||
and isSpace(context.str[context.cur]):
|
and isSpace(context.str[context.cur]):
|
||||||
context.cur = context.cur + 1;
|
context.cur = context.cur + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseNull(context) {
|
fun parseNull(context: Map) {
|
||||||
|
|
||||||
assert(context.cur < count(context)
|
assert(context.cur < count(context)
|
||||||
and context.str[context.cur] == 'n');
|
and context.str[context.cur] == 'n');
|
||||||
@@ -30,7 +30,7 @@ fun parseNull(context) {
|
|||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseTrue(context) {
|
fun parseTrue(context: Map) {
|
||||||
|
|
||||||
assert(context.cur < count(context)
|
assert(context.cur < count(context)
|
||||||
and context.str[context.cur] == 't');
|
and context.str[context.cur] == 't');
|
||||||
@@ -45,7 +45,7 @@ fun parseTrue(context) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseFalse(context) {
|
fun parseFalse(context: Map) {
|
||||||
|
|
||||||
assert(context.cur < count(context)
|
assert(context.cur < count(context)
|
||||||
and context.str[context.cur] == 'f');
|
and context.str[context.cur] == 'f');
|
||||||
@@ -61,14 +61,17 @@ fun parseFalse(context) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun skip(context, test_callback) {
|
fun dummy() {}
|
||||||
|
Func = type(dummy);
|
||||||
|
|
||||||
|
fun skip(context: Map, test_callback: Func) {
|
||||||
k = context.cur;
|
k = context.cur;
|
||||||
while k < count(context) and test_callback(context.str[k]):
|
while k < count(context) and test_callback(context.str[k]):
|
||||||
k = k + 1;
|
k = k + 1;
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseInteger(context) {
|
fun parseInteger(context: Map) {
|
||||||
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
||||||
|
|
||||||
buffer = 0;
|
buffer = 0;
|
||||||
@@ -84,7 +87,7 @@ fun parseInteger(context) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseFloating(context) {
|
fun parseFloating(context: Map) {
|
||||||
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
||||||
|
|
||||||
# It's ensured by the caller (parseIntegerOrFloating)
|
# It's ensured by the caller (parseIntegerOrFloating)
|
||||||
@@ -117,7 +120,7 @@ fun parseFloating(context) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseIntegerOrFloating(context) {
|
fun parseIntegerOrFloating(context: Map) {
|
||||||
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
||||||
|
|
||||||
# Is the first digit sequence followed by a dot
|
# Is the first digit sequence followed by a dot
|
||||||
@@ -132,7 +135,7 @@ fun parseIntegerOrFloating(context) {
|
|||||||
return parseInteger(context);
|
return parseInteger(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseValue(context) {
|
fun parseValue(context: Map) {
|
||||||
|
|
||||||
if context.cur == count(context):
|
if context.cur == count(context):
|
||||||
return none, "Source ended where a value was expected";
|
return none, "Source ended where a value was expected";
|
||||||
@@ -159,7 +162,7 @@ fun parseValue(context) {
|
|||||||
return val, err;
|
return val, err;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parse(str) {
|
fun parse(str: String) {
|
||||||
context = {str: str, cur: 0};
|
context = {str: str, cur: 0};
|
||||||
skipSpaces(context);
|
skipSpaces(context);
|
||||||
val, err = parseValue(context);
|
val, err = parseValue(context);
|
||||||
|
|||||||
@@ -208,15 +208,24 @@ static void emitInstrForFuncCallNode(CodegenContext *ctx, CallExprNode *expr,
|
|||||||
static void emitInstrForArgumentNode(CodegenContext *ctx, ArgumentNode *arg, int argidx)
|
static void emitInstrForArgumentNode(CodegenContext *ctx, ArgumentNode *arg, int argidx)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
* // Push the type of the argument
|
||||||
* PUSHTYP;
|
* PUSHTYP;
|
||||||
* <arg-type-0> // What if this isn't a type?
|
*
|
||||||
|
* // Evaluate the type annotation and make
|
||||||
|
* // sure that it evaluated to a type.
|
||||||
|
* <arg-type-0>
|
||||||
* PUSHTYP;
|
* PUSHTYP;
|
||||||
* PUSHTYPTYP;
|
* PUSHTYPTYP;
|
||||||
* EQL;
|
* EQL;
|
||||||
* JUMPIFANDPOP argument_annotation_0_not_type;
|
* JUMPIFANDPOP argument_annotation_0_not_type;
|
||||||
|
*
|
||||||
|
* // If the annotated type and the argument's
|
||||||
|
* // type match, jump to the argument assignment.
|
||||||
* EQL;
|
* EQL;
|
||||||
* JUMPIFANDPOP argument_type_ok;
|
* JUMPIFANDPOP argument_type_ok;
|
||||||
*
|
*
|
||||||
|
* // To the same for the next annotation.
|
||||||
|
*
|
||||||
* PUSHTYP;
|
* PUSHTYP;
|
||||||
* <arg-type-1>
|
* <arg-type-1>
|
||||||
* PUSHTYP;
|
* PUSHTYP;
|
||||||
@@ -239,6 +248,9 @@ static void emitInstrForArgumentNode(CodegenContext *ctx, ArgumentNode *arg, int
|
|||||||
* argument_annotation_0_not_a_type:
|
* argument_annotation_0_not_a_type:
|
||||||
* ERROR "Argument N annotation M isn't a type";
|
* ERROR "Argument N annotation M isn't a type";
|
||||||
* argument_type_ok:
|
* argument_type_ok:
|
||||||
|
*
|
||||||
|
* // At this point we know that the argument has
|
||||||
|
* // a valid type.
|
||||||
* ASS <arg-name>;
|
* ASS <arg-name>;
|
||||||
* POP 1;
|
* POP 1;
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user