Merge pull request #203 from ThakeeNathees/syntax-change

function and else if keywords are changed.
This commit is contained in:
Thakee Nathees 2022-04-17 07:49:52 +05:30 committed by GitHub
commit 2262089948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 122 additions and 96 deletions

View File

@ -115,7 +115,7 @@ typedef enum {
TK_AS, // as TK_AS, // as
TK_DEF, // def TK_DEF, // def
TK_NATIVE, // native (C function declaration) TK_NATIVE, // native (C function declaration)
TK_FUNC, // func (literal function) TK_FUNCTION, // function (literal function)
TK_END, // end TK_END, // end
TK_NULL, // null TK_NULL, // null
@ -131,7 +131,6 @@ typedef enum {
TK_WHILE, // while TK_WHILE, // while
TK_FOR, // for TK_FOR, // for
TK_IF, // if TK_IF, // if
TK_ELSIF, // elsif
TK_ELSE, // else TK_ELSE, // else
TK_BREAK, // break TK_BREAK, // break
TK_CONTINUE, // continue TK_CONTINUE, // continue
@ -178,7 +177,7 @@ static _Keyword _keywords[] = {
{ "as", 2, TK_AS }, { "as", 2, TK_AS },
{ "def", 3, TK_DEF }, { "def", 3, TK_DEF },
{ "native", 6, TK_NATIVE }, { "native", 6, TK_NATIVE },
{ "func", 4, TK_FUNC }, { "function", 8, TK_FUNCTION },
{ "end", 3, TK_END }, { "end", 3, TK_END },
{ "null", 4, TK_NULL }, { "null", 4, TK_NULL },
{ "in", 2, TK_IN }, { "in", 2, TK_IN },
@ -192,7 +191,6 @@ static _Keyword _keywords[] = {
{ "while", 5, TK_WHILE }, { "while", 5, TK_WHILE },
{ "for", 3, TK_FOR }, { "for", 3, TK_FOR },
{ "if", 2, TK_IF }, { "if", 2, TK_IF },
{ "elsif", 5, TK_ELSIF },
{ "else", 4, TK_ELSE }, { "else", 4, TK_ELSE },
{ "break", 5, TK_BREAK }, { "break", 5, TK_BREAK },
{ "continue", 8, TK_CONTINUE }, { "continue", 8, TK_CONTINUE },
@ -1180,8 +1178,7 @@ static void skipNewLines(Compiler* compiler) {
matchLine(compiler); matchLine(compiler);
} }
// Match semi collon, multiple new lines or peek 'end', 'else', 'elsif' // Match semi collon, multiple new lines or peek 'end', 'else' keywords.
// keywords.
static bool matchEndStatement(Compiler* compiler) { static bool matchEndStatement(Compiler* compiler) {
if (match(compiler, TK_SEMICOLLON)) { if (match(compiler, TK_SEMICOLLON)) {
skipNewLines(compiler); skipNewLines(compiler);
@ -1191,9 +1188,8 @@ static bool matchEndStatement(Compiler* compiler) {
return true; return true;
// In the below statement we don't require any new lines or semicolons. // In the below statement we don't require any new lines or semicolons.
// 'if cond then stmnt1 elsif cond2 then stmnt2 else stmnt3 end' // 'if cond then stmnt1 else if cond2 then stmnt2 else stmnt3 end'
if (peek(compiler) == TK_END || peek(compiler) == TK_ELSE || if (peek(compiler) == TK_END || peek(compiler) == TK_ELSE)
peek(compiler) == TK_ELSIF)
return true; return true;
return false; return false;
@ -1433,7 +1429,7 @@ static void compileExpression(Compiler* compiler);
static void exprLiteral(Compiler* compiler); static void exprLiteral(Compiler* compiler);
static void exprInterpolation(Compiler* compiler); static void exprInterpolation(Compiler* compiler);
static void exprFunc(Compiler* compiler); static void exprFunction(Compiler* compiler);
static void exprName(Compiler* compiler); static void exprName(Compiler* compiler);
static void exprOr(Compiler* compiler); static void exprOr(Compiler* compiler);
@ -1509,7 +1505,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
/* TK_AS */ NO_RULE, /* TK_AS */ NO_RULE,
/* TK_DEF */ NO_RULE, /* TK_DEF */ NO_RULE,
/* TK_EXTERN */ NO_RULE, /* TK_EXTERN */ NO_RULE,
/* TK_FUNC */ { exprFunc, NULL, NO_INFIX }, /* TK_FUNCTION */ { exprFunction, NULL, NO_INFIX },
/* TK_END */ NO_RULE, /* TK_END */ NO_RULE,
/* TK_NULL */ { exprValue, NULL, NO_INFIX }, /* TK_NULL */ { exprValue, NULL, NO_INFIX },
/* TK_IN */ { NULL, exprBinaryOp, PREC_TEST }, /* TK_IN */ { NULL, exprBinaryOp, PREC_TEST },
@ -1523,7 +1519,6 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
/* TK_WHILE */ NO_RULE, /* TK_WHILE */ NO_RULE,
/* TK_FOR */ NO_RULE, /* TK_FOR */ NO_RULE,
/* TK_IF */ NO_RULE, /* TK_IF */ NO_RULE,
/* TK_ELSIF */ NO_RULE,
/* TK_ELSE */ NO_RULE, /* TK_ELSE */ NO_RULE,
/* TK_BREAK */ NO_RULE, /* TK_BREAK */ NO_RULE,
/* TK_CONTINUE */ NO_RULE, /* TK_CONTINUE */ NO_RULE,
@ -1676,7 +1671,7 @@ static void exprInterpolation(Compiler* compiler) {
} }
static void exprFunc(Compiler* compiler) { static void exprFunction(Compiler* compiler) {
compileFunction(compiler, true); compileFunction(compiler, true);
} }
@ -2489,8 +2484,8 @@ static void compileBlockBody(Compiler* compiler, BlockType type) {
} }
TokenType next = peek(compiler); TokenType next = peek(compiler);
while (!(next == TK_END || next == TK_EOF || ( while (!(next == TK_END || next == TK_EOF ||
(type == BLOCK_IF) && (next == TK_ELSE || next == TK_ELSIF)))) { ((type == BLOCK_IF) && (next == TK_ELSE)))) {
compileStatement(compiler); compileStatement(compiler);
skipNewLines(compiler); skipNewLines(compiler);
@ -2849,7 +2844,7 @@ static void compileExpression(Compiler* compiler) {
parsePrecedence(compiler, PREC_LOWEST); parsePrecedence(compiler, PREC_LOWEST);
} }
static void compileIfStatement(Compiler* compiler, bool elsif) { static void compileIfStatement(Compiler* compiler, bool else_if) {
skipNewLines(compiler); skipNewLines(compiler);
compileExpression(compiler); //< Condition. compileExpression(compiler); //< Condition.
@ -2858,38 +2853,40 @@ static void compileIfStatement(Compiler* compiler, bool elsif) {
compileBlockBody(compiler, BLOCK_IF); compileBlockBody(compiler, BLOCK_IF);
if (match(compiler, TK_ELSIF)) { if (match(compiler, TK_ELSE)) {
// Jump pass else. if (match(compiler, TK_IF)) { //< Compile 'else if'.
emitOpcode(compiler, OP_JUMP); // Jump pass else.
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched. emitOpcode(compiler, OP_JUMP);
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
// if (false) jump here. // if (false) jump here.
patchJump(compiler, ifpatch); patchJump(compiler, ifpatch);
compilerEnterBlock(compiler); compilerEnterBlock(compiler);
compileIfStatement(compiler, true); compileIfStatement(compiler, true);
compilerExitBlock(compiler); compilerExitBlock(compiler);
patchJump(compiler, exit_jump); patchJump(compiler, exit_jump);
} else if (match(compiler, TK_ELSE)) { } else { //< Compile 'else'.
// Jump pass else. // Jump pass else.
emitOpcode(compiler, OP_JUMP); emitOpcode(compiler, OP_JUMP);
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched. int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
patchJump(compiler, ifpatch); patchJump(compiler, ifpatch);
compileBlockBody(compiler, BLOCK_ELSE); compileBlockBody(compiler, BLOCK_ELSE);
patchJump(compiler, exit_jump); patchJump(compiler, exit_jump);
}
} else { } else {
patchJump(compiler, ifpatch); patchJump(compiler, ifpatch);
} }
// elsif will not consume the 'end' keyword as it'll be leaved to be consumed // 'else if' will not consume the 'end' keyword as it'll be leaved to be
// by it's 'if'. // consumed by it's 'if'.
if (!elsif) { if (!else_if) {
skipNewLines(compiler); skipNewLines(compiler);
consume(compiler, TK_END, "Expected 'end' after statement end."); consume(compiler, TK_END, "Expected 'end' after statement end.");
} }

View File

@ -51,52 +51,52 @@ def execute(expr)
if ptr >= mem.length then list_append(mem, 0) end if ptr >= mem.length then list_append(mem, 0) end
## Decrement the data pointer (to point to the next cell to the left). ## Decrement the data pointer (to point to the next cell to the left).
elsif c == '<' else if c == '<'
ptr -= 1 ptr -= 1
if ptr < 0 then assert(false, "ip < 0") end if ptr < 0 then assert(false, "ip < 0") end
## Increment (increase by one) the byte at the data pointer. ## Increment (increase by one) the byte at the data pointer.
elsif c == '+' else if c == '+'
if mem[ptr] == 255 then mem[ptr] = 0 if mem[ptr] == 255 then mem[ptr] = 0
else mem[ptr] += 1 end else mem[ptr] += 1 end
## Decrement (decrease by one) the byte at the data pointer. ## Decrement (decrease by one) the byte at the data pointer.
elsif c == '-' else if c == '-'
if mem[ptr] == 0 then mem[ptr] = 255 if mem[ptr] == 0 then mem[ptr] = 255
else mem[ptr] -= 1 end else mem[ptr] -= 1 end
## output the byte at the data pointer. ## output the byte at the data pointer.
elsif c == '.' else if c == '.'
write(str_chr(mem[ptr])) write(str_chr(mem[ptr]))
elsif c == ',' else if c == ','
assert(false, "Currently input isn't supported in pocketlang.") assert(false, "Currently input isn't supported in pocketlang.")
## if the byte at the data pointer is zero, then instead of moving the ## if the byte at the data pointer is zero, then instead of moving the
## instruction pointer forward to the next command, jump it forward to ## instruction pointer forward to the next command, jump it forward to
## the command after the matching ] command. ## the command after the matching ] command.
elsif c == '[' and mem[ptr] == 0 else if c == '[' and mem[ptr] == 0
open = 0 open = 0
while true while true
i += 1 i += 1
if expr[i] == ']' and open == 0 then break end if expr[i] == ']' and open == 0 then break end
if expr[i] == '[' then open += 1 if expr[i] == '[' then open += 1
elsif expr[i] == ']' then open -= 1 else if expr[i] == ']' then open -= 1
end assert(open >= 0) end assert(open >= 0)
end end
## if the byte at the data pointer is nonzero, then instead of moving the ## if the byte at the data pointer is nonzero, then instead of moving the
## instruction pointer forward to the next command, jump it back to the ## instruction pointer forward to the next command, jump it back to the
## command after the matching [ command ## command after the matching [ command
elsif c == ']' and mem[ptr] != 0 else if c == ']' and mem[ptr] != 0
open = 0 open = 0
while true while true
i -= 1 i -= 1
if expr[i] == '[' and open == 0 then break end if expr[i] == '[' and open == 0 then break end
if expr[i] == ']' then open -= 1 if expr[i] == ']' then open -= 1
elsif expr[i] == '[' then open += 1 else if expr[i] == '[' then open += 1
end assert(open <= 0) end assert(open <= 0)
end end

View File

@ -2,8 +2,8 @@
for i in 1..100 for i in 1..100
if i%3 == 0 and i%5 == 0 then print('fizzbuzz') if i%3 == 0 and i%5 == 0 then print('fizzbuzz')
elsif i%3 == 0 then print('fizz') else if i%3 == 0 then print('fizz')
elsif i%5 == 0 then print('buzz') else if i%5 == 0 then print('buzz')
else print(i) else print(i)
end end
end end

32
tests/examples/matrix.pk Normal file
View File

@ -0,0 +1,32 @@
## Multiply two matrices.
## A is 3x3 matrix
A = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
## B is 3x4 matrix.
B = [[4, 6, 3, 2],
[8, 7, 0, 2],
[6, 0, 9, 4]]
## Result is 3x4 matrix.
R = [[0,0,0,0],
[0,0,0,0],
[0,0,0,0]]
## Iterate through rows of A.
for i in 0..(A.length)
## Iterate through columns of B.
for j in 0..(B[0].length)
for k in 0..(B.length)
R[i][j] += A[i][k] * B[k][j]
end
end
end
for row in R
print(row)
end

View File

@ -1,19 +0,0 @@
## Run pocket palette.pk > palette.ppm
## Open palatte.ppm with any image viwer which support ppm image
## (ex: photoshop, gimp, libre office draw, ...)
blue = 200
print("P3")
print(255, 255)
print(255)
from lang import write
for r in 0..255
for g in 0..255
write(r, ' ', g, ' ', blue, ' ')
end
write('\n')
end

View File

@ -18,7 +18,7 @@ assert(0xa1b2c3 == 10597059 and 0xff == 255)
assert(0xffffffffffffffff == 18446744073709551615) assert(0xffffffffffffffff == 18446744073709551615)
## Lists test. ## Lists test.
l1 = [1, false, null, func print('hello') end, true] l1 = [1, false, null, function print('hello') end, true]
assert(l1[4]) assert(l1[4])
l1[3] = null; assert(!l1[3]) l1[3] = null; assert(!l1[3])
l1 = [] + [] ; assert(l1.length == 0) l1 = [] + [] ; assert(l1.length == 0)
@ -45,7 +45,7 @@ assert(math.ceil(1.1) == math.floor(2.9))
## Logical statement test ## Logical statement test
val = 0; a = false; b = true val = 0; a = false; b = true
get_true = func return true end get_true = function return true end
if a and b then assert(false) end if a and b then assert(false) end
if a or b then val = 42 else assert(false) end assert(val == 42) if a or b then val = 42 else assert(false) end assert(val == 42)
if get_true() or false then val = 12 end assert(val == 12) if get_true() or false then val = 12 end assert(val == 12)

View File

@ -2,15 +2,15 @@
## Simple upvalue. ## Simple upvalue.
def f1 def f1
local = "foo" local = "foo"
return func return function
return local return local
end end
end end
assert(f1()() == "foo") assert(f1()() == "foo")
def add3(x) def add3(x)
return func(y) return function(y)
return func(z) return function(z)
return x + y + z return x + y + z
end end
end end
@ -21,8 +21,8 @@ assert(add3(7)(6)(4) == 17);
## Upvalue external to the inner function. ## Upvalue external to the inner function.
def f2 def f2
local = "bar" local = "bar"
return func return function
fn = func fn = function
return local return local
end end
return fn return fn
@ -33,10 +33,10 @@ assert(f2()()() == "bar")
## Check if upvalues are shared between closures. ## Check if upvalues are shared between closures.
def f3 def f3
local = "baz" local = "baz"
_fn1 = func(x) _fn1 = function(x)
local = x local = x
end end
_fn2 = func _fn2 = function
return local return local
end end
return [_fn1, _fn2] return [_fn1, _fn2]
@ -52,7 +52,7 @@ def f4
j = i ## 'i' is shared, but 'j' doesn't j = i ## 'i' is shared, but 'j' doesn't
list_append( list_append(
a, a,
func function
return x + j return x + j
end end
) )
@ -66,13 +66,13 @@ assert(a[1]() == 21)
def f5 def f5
l1 = 12 l1 = 12
return func ## c1 return function ## c1
l2 = 34 l2 = 34
return func ## c2 return function ## c2
l3 = 56 l3 = 56
return func ## c3 return function ## c3
return func ## c4 return function ## c4
return func ## c5 return function ## c5
return l1 + l2 + l3 return l1 + l2 + l3
end end
end end

View File

@ -1,27 +1,27 @@
## If statements. ## If statements.
variable = null ## Will be changed by the control flow. variable = null ## Will be changed by the control flow.
unreachable = func assert(false, 'Unreachable') end unreachable = function assert(false, 'Unreachable') end
if true then variable = 42 else unreachable() end if true then variable = 42 else unreachable() end
assert(variable == 42, 'If statement failed.') assert(variable == 42, 'If statement failed.')
if false then unreachable() if false then unreachable()
elsif true then variable = null else if true then variable = null
else unreachable() end else unreachable() end
assert(variable == null) assert(variable == null)
if false then unreachable() if false then unreachable()
elsif false then unreachable() else if false then unreachable()
elsif false then unreachable() else if false then unreachable()
else variable = "changed" end else variable = "changed" end
assert(variable == "changed") assert(variable == "changed")
if false then unreachable() if false then unreachable()
elsif true else if true
if false if false
unreachable() unreachable()
elsif true else if true
variable = 123 variable = 123
else else
unreachable() unreachable()
@ -39,9 +39,9 @@ assert(variable == 1212)
while true while true
variable = 22 variable = 22
if true then elsif false then end if true then else if false then end
if false if false
elsif true else if true
variable += 2300 variable += 2300
end end
variable += 1 variable += 1
@ -55,6 +55,21 @@ for k in map
end end
assert(sum == 54) assert(sum == 54)
val = 2
if val == 1 then val = null
else if val == 2 then val = 'foo'
else val = null
end
assert(val == 'foo')
val = 2
if val == 1 then val = null
else
if val == 2 then val = 'bar'
end ##< Need an extra end since 'else if' != 'else \n if'.
end
assert(val == 'bar')
# If we got here, that means all test were passed. # If we got here, that means all test were passed.
print('All TESTS PASSED') print('All TESTS PASSED')

View File

@ -26,7 +26,7 @@ assert([1, 2, 3].length == 3)
## Function ## Function
assert(print.arity == -1) assert(print.arity == -1)
assert(hex.arity == 1) assert(hex.arity == 1)
assert(func(a, b)end .arity == 2) assert(function(a, b)end .arity == 2)
assert(print.name == "print") assert(print.name == "print")
def fn(p1, p2, p3) end def fn(p1, p2, p3) end
assert(fn.name == "fn") assert(fn.name == "fn")

View File

@ -9,7 +9,7 @@ assert(f3('a', 'b', 'c', 'd') == 'c')
## Local variables of inner funcions. ## Local variables of inner funcions.
def f4 def f4
l1 = 3.14 l1 = 3.14
f5 = func f5 = function
l2 = 42 l2 = 42
return l2 return l2
end end

View File

@ -44,27 +44,27 @@ def eval(expr, ind)
end end
return [val, ind] return [val, ind]
elsif c == '+' else if c == '+'
r = binary_op(expr, ind) r = binary_op(expr, ind)
if not r[0] then return [null, -1] end if not r[0] then return [null, -1] end
return [r[1] + r[2], r[3]] return [r[1] + r[2], r[3]]
elsif c == '-' else if c == '-'
r = binary_op(expr, ind) r = binary_op(expr, ind)
if not r[0] then return [null, -1] end if not r[0] then return [null, -1] end
return [r[1] - r[2], r[3]] return [r[1] - r[2], r[3]]
elsif c == '*' else if c == '*'
r = binary_op(expr, ind) r = binary_op(expr, ind)
if not r[0] then return [null, -1] end if not r[0] then return [null, -1] end
return [r[1] * r[2], r[3]] return [r[1] * r[2], r[3]]
elsif c == '/' else if c == '/'
r = binary_op(expr, ind) r = binary_op(expr, ind)
if not r[0] then return [null, -1] end if not r[0] then return [null, -1] end
return [r[1] / r[2], r[3]] return [r[1] / r[2], r[3]]
elsif isnum(c) else if isnum(c)
val = str_ord(c) - str_ord('0') val = str_ord(c) - str_ord('0')
assert(0 <= val and val < 10) assert(0 <= val and val < 10)
return [val, ind] return [val, ind]

View File

@ -37,6 +37,7 @@ TEST_SUITE = {
"examples/fib.pk", "examples/fib.pk",
"examples/fizzbuzz.pk", "examples/fizzbuzz.pk",
"examples/helloworld.pk", "examples/helloworld.pk",
"examples/matrix.pk",
"examples/pi.pk", "examples/pi.pk",
"examples/prime.pk", "examples/prime.pk",
), ),