a bunch of grammar fixes

This commit is contained in:
Francesco Cozzuto
2022-08-17 23:58:28 +02:00
parent 7e0144faa3
commit 71e8a9e4cb
14 changed files with 42 additions and 75 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ Noja is a high level programming language implemented as a learning exercise. St
The use-cases of Noja are the same as Python since their abstraction level is comparable. The syntax is more similar to the C-family of languages though (curly brackets to denote scope). The use-cases of Noja are the same as Python since their abstraction level is comparable. The syntax is more similar to the C-family of languages though (curly brackets to denote scope).
## A Noja program ## A Noja program
A Noja program is a sequence of statements separated by semi-colons (with some exceptions). The statements can be o various kinds: A Noja program is a sequence of statements separated by semi-colons (with some exceptions). The statements can be of various kinds:
* expressions * expressions
* function definitions * function definitions
* if-else branches * if-else branches
+5 -4
View File
@@ -128,12 +128,12 @@ Lists are defined as a comma-separated list of expressions between square bracke
[none, 2 + 1, true]; [none, 2 + 1, true];
``` ```
The `n`-th list can be accessed using the `[]` notation: The `n`-th list element can be accessed using the `[]` notation:
```py ```py
ls = [true, false, none]; ls = [true, false, none];
ls[1]; # false ls[1]; # false
``` ```
where the list value is followed by `[..]` which contain the index of the item to retrieve. where the list value is followed by `[..]` which contains the index of the item to retrieve.
The index may be evaluated dynamically, but it will trigger a runtime error if it doesn't evaluate to an integer value The index may be evaluated dynamically, but it will trigger a runtime error if it doesn't evaluate to an integer value
```py ```py
@@ -142,7 +142,7 @@ ls[0 + 2]; # OK!
ls[true or false]; # Runtime error!! ls[true or false]; # Runtime error!!
``` ```
To append a value to a list, increasing it's size, you can just insert the new value at the first unused position (which will have index equal to the current list size). As we'll see in the built-in chapter, to get the size of a list one can use the `count` function. Which means appending to a list can be done like this: To append a value to a list, increasing its size, you can just insert the new value at the first unused position (which will have index equal to the current list size). As we'll see in the built-in chapter, to get the size of a list one can use the `count` function. Which means appending to a list can be done like this:
```py ```py
ls = [1, 2, 3]; ls = [1, 2, 3];
ls[count(ls)] = 4; ls[count(ls)] = 4;
@@ -170,7 +170,7 @@ a = {"name": "Francesco", "age": 25};
b = {name: "Francesco", age: 25}; b = {name: "Francesco", age: 25};
``` ```
If you don't want to use the identifier as key but evaluate it as a variable to use it's value as key, then you can explicitly tell the interpreter that it's an expression If you don't want to use the identifier's text as key but evaluate it as a variable to use it's value as key, then you must explicitly tell the interpreter that it's an expression
```py ```py
name = "x"; name = "x";
@@ -179,6 +179,7 @@ a = { "x": "Francesco", "age": 25};
b = {(name): "Francesco", age: 25}; b = {(name): "Francesco", age: 25};
c = { +name: "Francesco", age: 25}; c = { +name: "Francesco", age: 25};
``` ```
Note that the `+` unary operator and the `(..)` are no-operations in this context.
Because of compound statements (discussed in the next chapter), an expression can't start with the `{` of a map literal because the interpreter will assume it's a compount statement. Because of compound statements (discussed in the next chapter), an expression can't start with the `{` of a map literal because the interpreter will assume it's a compount statement.
The following statement is invalid The following statement is invalid
+1 -1
View File
@@ -13,7 +13,7 @@ Unlike expressions statements, they don't end with a `;`.
The condition may be any type of expression, but must evaluate to a boolean type. No implicit casts are performed. The condition may be any type of expression, but must evaluate to a boolean type. No implicit casts are performed.
When the `else` block is empty, in can me omitted: When the `else` block is empty, it can me omitted:
```py ```py
if condition: { if condition: {
# Executed when the condition is true # Executed when the condition is true
+1 -1
View File
@@ -13,7 +13,7 @@ while condition: {
``` ```
as you can see, it doesn't need an ending `;`. as you can see, it doesn't need an ending `;`.
when the interpreter encounters a while statement, it evaluates the condition. If the condition is true, it executes it's body. When the execution of the inner block of code is completed, the execution jumps back to the condition, evaluating it again. If it's again true, the inner code is executed again, else the execution jumps after the while statement. This mechanism can go on potentially for ever! When the interpreter encounters a while statement, it evaluates the condition. If the condition is true, it executes its body. When the execution of the inner block of code is completed, the execution jumps back to the condition, evaluating it again. If it's again true, the inner code is executed again, else the execution jumps after the while statement. This mechanism can go on potentially for ever!
Like for if-else statements, when the inner block only has one statement, you can drop the `{}` Like for if-else statements, when the inner block only has one statement, you can drop the `{}`
```py ```py
+2 -2
View File
@@ -1,5 +1,5 @@
# Functions # Functions
Function definition statements always start with the `fun` keyword, followed by it's name, argument list and then body. Function definition statements always start with the `fun` keyword, followed by its name, argument list and then body.
Here are some examples of function definitions: Here are some examples of function definitions:
```py ```py
@@ -46,7 +46,7 @@ abc = 10;
``` ```
## Functions calls and return values ## Functions calls and return values
To execute a function in an expression, it's name must be followed by an argument list enclosed in brackets `(..)`. All functions return at least one value, which may be `none` when a function has no useful value to be returned. To execute a function in an expression, its name must be followed by an argument list enclosed in brackets `(..)`. All functions return at least one value, which may be `none` when a function has no useful value to be returned.
To specify the return value of a function, one must use the `return` statement To specify the return value of a function, one must use the `return` statement
```py ```py
+1 -1
View File
@@ -1,5 +1,5 @@
# This script implements a circular queue and # This script implements a circular queue and
# it's relative tests! # its relative tests!
fun newCircularQueue(T: Type = int, max: int = 3) { fun newCircularQueue(T: Type = int, max: int = 3) {
+21 -55
View File
@@ -5,9 +5,10 @@ fun isSpace(c: String)
or c == "\n"; or c == "\n";
fun isDigit(c: String) { fun isDigit(c: String) {
u = unicode(c); d = string.ord(c)
d = u - unicode("0"); - string.ord("0");
return d >= 0 and d <= 9; return d >= 0
and d <= 9;
} }
fun skipSpaces(context: Map) { fun skipSpaces(context: Map) {
@@ -68,7 +69,8 @@ Func = type(dummy);
fun skip(context: Map, test_callback: Func) { fun skip(context: Map, test_callback: Func) {
k = context.cur; k = context.cur;
while k < count(context.str) and test_callback(context.str[k]): while k < count(context.str)
and test_callback(context.str[k]):
k = k + 1; k = k + 1;
return k; return k;
} }
@@ -80,7 +82,7 @@ fun parseInteger(context: Map) {
do { do {
c = context.str[context.cur]; c = context.str[context.cur];
d = unicode(c) - unicode('0'); d = string.ord(c) - string.ord('0');
buffer = buffer * 10 + d; buffer = buffer * 10 + d;
context.cur = context.cur + 1; context.cur = context.cur + 1;
} while context.cur < count(context.str) } while context.cur < count(context.str)
@@ -90,7 +92,8 @@ fun parseInteger(context: Map) {
} }
fun parseFloating(context: Map) { fun parseFloating(context: Map) {
assert(context.cur < count(context.str) and isDigit(context.str[context.cur])); assert(context.cur < count(context.str)
and isDigit(context.str[context.cur]));
# It's ensured by the caller (parseIntegerOrFloating) # It's ensured by the caller (parseIntegerOrFloating)
# that now the strings contains two sequences of # that now the strings contains two sequences of
@@ -101,7 +104,7 @@ fun parseFloating(context: Map) {
# Scan the integer part. # Scan the integer part.
do { do {
c = context.str[context.cur]; c = context.str[context.cur];
d = unicode(c) - unicode('0'); d = string.ord(c) - string.ord('0');
buffer = buffer * 10 + d; buffer = buffer * 10 + d;
context.cur = context.cur + 1; context.cur = context.cur + 1;
} while context.str[context.cur] != "."; } while context.str[context.cur] != ".";
@@ -112,18 +115,19 @@ fun parseFloating(context: Map) {
q = 1; q = 1;
do { do {
c = context.str[context.cur]; c = context.str[context.cur];
d = unicode(c) - unicode('0'); d = string.ord(c) - string.ord('0');
q = q / 10; q = q / 10;
buffer = buffer + q * d; buffer = buffer + q * d;
context.cur = context.cur + 1; context.cur = context.cur + 1;
} while context.cur < count(context.str) } while context.cur < count(context.str)
and isDigit(context); and isDigit(context.str[context.cur+1]);
return buffer; return buffer;
} }
fun parseIntegerOrFloating(context: Map) { fun parseIntegerOrFloating(context: Map) {
assert(context.cur < count(context.str) and isDigit(context.str[context.cur])); assert(context.cur < count(context.str)
and isDigit(context.str[context.cur]));
# Is the first digit sequence followed by a dot # Is the first digit sequence followed by a dot
# and then one or more digits? # and then one or more digits?
@@ -212,20 +216,13 @@ fun parseValue(context: Map) {
return none, "Source ended where a value was expected"; return none, "Source ended where a value was expected";
c = context.str[context.cur]; c = context.str[context.cur];
if c == "{": if c == "{": val, err = parseObject(context);
val, err = parseObject(context); else if c == "[": val, err = parseArray(context);
else if c == "[": else if c == '"': val, err = parseString(context);
val, err = parseArray(context); else if isDigit(c): val, err = parseIntegerOrFloating(context);
else if c == '"': else if c == 'n': val, err = parseNull(context);
val, err = parseString(context); else if c == 't': val, err = parseTrue(context);
else if isDigit(c): else if c == 'f': val, err = parseFalse(context);
val, err = parseIntegerOrFloating(context);
else if c == 'n':
val, err = parseNull(context);
else if c == 't':
val, err = parseTrue(context);
else if c == 'f':
val, err = parseFalse(context);
else { else {
val = none; val = none;
err = string.cat("Unexepected character \"", c, "\" where a value was expected"); err = string.cat("Unexepected character \"", c, "\" where a value was expected");
@@ -234,39 +231,8 @@ fun parseValue(context: Map) {
} }
fun parse(str: String) { 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);
return val, err; return val, err;
} }
fun compareAny(A, B) {
fun compareLists(A: List, B: List) {
n = count(A);
if n != count(B):
return flase;
i = 0;
while i < n: {
if not compareAny(A[i], B[i]):
return false;
i = i + 1;
}
return true;
}
T = type(A);
if T != type(B):
return false;
if T == List:
return compareLists(A, B);
if T == Map:
error("Maps aren't supported yet!");
return A == B;
}
+1 -1
View File
@@ -103,7 +103,7 @@ CLI_SRCDIR = $(SRCDIR)/$(CLI_SUBDIR)
TST_SRCDIR = $(SRCDIR)/$(TST_SUBDIR) TST_SRCDIR = $(SRCDIR)/$(TST_SUBDIR)
# Each program that is being build uses as object # Each program that is being build uses as object
# cache a subfolder of OBJDIR called like the it's # cache a subfolder of OBJDIR called like the its
# source tree base folder in SRCDIR. # source tree base folder in SRCDIR.
LIB_OBJDIR = $(OBJDIR)/$(LIB_SUBDIR) LIB_OBJDIR = $(OBJDIR)/$(LIB_SUBDIR)
CLI_OBJDIR = $(OBJDIR)/$(CLI_SUBDIR) CLI_OBJDIR = $(OBJDIR)/$(CLI_SUBDIR)
+3 -3
View File
@@ -145,7 +145,7 @@ static bool parseIntegerOperand(Context *ctx, Error *error, Operand *op)
long long int buffer = 0; long long int buffer = 0;
do { do {
// Transform each digit into it's integer value. // Transform each digit into its integer value.
int d = ctx->str[ctx->cur] - '0'; int d = ctx->str[ctx->cur] - '0';
assert(d >= 0 && d <= 9); assert(d >= 0 && d <= 9);
@@ -179,7 +179,7 @@ static bool parseFloatingOperand(Context *ctx, Error *error, Operand *op)
double buffer = 0; double buffer = 0;
do { do {
// Transform each digit into it's integer value. // Transform each digit into its integer value.
int d = ctx->str[ctx->cur] - '0'; int d = ctx->str[ctx->cur] - '0';
assert(d >= 0 && d <= 9); assert(d >= 0 && d <= 9);
@@ -196,7 +196,7 @@ static bool parseFloatingOperand(Context *ctx, Error *error, Operand *op)
double q = 1; double q = 1;
do { do {
// Transform each digit into it's integer value. // Transform each digit into its integer value.
int d = ctx->str[ctx->cur] - '0'; int d = ctx->str[ctx->cur] - '0';
assert(d >= 0 && d <= 9); assert(d >= 0 && d <= 9);
+1 -1
View File
@@ -1,3 +1,3 @@
Here are implemented the language's builtin variables. Each file defines it's values and exposes them through an array of `StaticMapSlot`s. These values can then be accessed from within the language by wrapping these arrays in static map objects (check src/o_staticmap.c to know more). Here are implemented the language's builtin variables. Each file defines its values and exposes them through an array of `StaticMapSlot`s. These values can then be accessed from within the language by wrapping these arrays in static map objects (check src/o_staticmap.c to know more).
The array of `StaticMapSlot`s defined by `basic.c` is the root of the builtin object tree. All other arrays are referred by it. The array of `StaticMapSlot`s defined by `basic.c` is the root of the builtin object tree. All other arrays are referred by it.
+1 -1
View File
@@ -17,7 +17,7 @@ Executable *compile(Source *src, Error *error, CompilationErrorType *errtyp)
return NULL; return NULL;
} }
// NOTE: The AST is stored in the BPAlloc. It's // NOTE: The AST is stored in the BPAlloc. Its
// lifetime is the same as the pool. // lifetime is the same as the pool.
AST *ast = parse(src, alloc, error); AST *ast = parse(src, alloc, error);
+1 -1
View File
@@ -56,7 +56,7 @@
** | HOW ARE POINTERS UPDATED? | ** | HOW ARE POINTERS UPDATED? |
** | Basically, when an object is moved from the old to the new heap, the | ** | Basically, when an object is moved from the old to the new heap, the |
** | location of the object in the old heap is overwritten with a placeholder | ** | location of the object in the old heap is overwritten with a placeholder |
** | object that holds the new location. Then all of it's references are | ** | object that holds the new location. Then all of its references are |
** | iterated over and if they refer to placeholders they're updated with the | ** | iterated over and if they refer to placeholders they're updated with the |
** | new location of the object. If the references don't refer to placeholder | ** | new location of the object. If the references don't refer to placeholder |
** | objects, then the referred objects are moved too. This is a recursive | ** | objects, then the referred objects are moved too. This is a recursive |
+1 -1
View File
@@ -99,7 +99,7 @@ Source *Source_FromFile(const char *file, Error *error)
return NULL; return NULL;
} }
// Open the file and get it's size. // Open the file and get its size.
// at the end of the block, the file // at the end of the block, the file
// cursor will point at the start of // cursor will point at the start of
// the file. // the file.
+1 -1
View File
@@ -243,7 +243,7 @@ int utf8_sequence_to_utf32_codepoint(const char *utf8_data, int nbytes, uint32_t
** value is equal to [nbytes]. ** value is equal to [nbytes].
** **
** NOTE: You can check the validity of a UTF-8 string ** NOTE: You can check the validity of a UTF-8 string
** by calling this function and checking that it's ** by calling this function and checking that its
** return value is not negative. ** return value is not negative.
*/ */
int utf8_strlen(const char *utf8_data, int nbytes) int utf8_strlen(const char *utf8_data, int nbytes)