Improvements to if blocks and generation

This commit is contained in:
Lewin Kelly 2024-02-21 23:33:18 +00:00
parent 900f79732a
commit 86892f2c22
2 changed files with 153 additions and 128 deletions

View File

@ -93,42 +93,6 @@ local function BlockExpr(startToken: Token, expressions: { Expr }): BlockExpr
} }
end end
type IfExpr = Expr & {
condition: Expr,
block: BlockExpr,
}
local function IfExpr(
startToken: Token,
condition: Expr,
block: BlockExpr
): IfExpr
return {
startToken = startToken,
kind = "if" :: ExprKind,
condition = condition,
block = block,
}
end
type ElseIfExpr = Expr & {
condition: Expr,
block: BlockExpr,
}
local function ElseIfExpr(
startToken: Token,
condition: Expr,
block: BlockExpr
): ElseIfExpr
return {
startToken = startToken,
kind = "elseif" :: ExprKind,
condition = condition,
block = block,
}
end
type ElseExpr = Expr & { type ElseExpr = Expr & {
block: Expr, block: Expr,
} }
@ -141,6 +105,48 @@ local function ElseExpr(startToken: Token, block: BlockExpr): ElseExpr
} }
end end
type ElseIfExpr = Expr & {
condition: Expr,
block: BlockExpr,
next: (ElseIfExpr | ElseExpr)?,
}
local function ElseIfExpr(
startToken: Token,
condition: Expr,
block: BlockExpr,
next: (ElseIfExpr | ElseExpr)?
): ElseIfExpr
return {
startToken = startToken,
kind = "elseif" :: ExprKind,
condition = condition,
block = block,
next = next,
}
end
type IfExpr = Expr & {
condition: Expr,
block: BlockExpr,
next: (ElseIfExpr | ElseExpr)?,
}
local function IfExpr(
startToken: Token,
condition: Expr,
block: BlockExpr,
next: (ElseIfExpr | ElseExpr)?
): IfExpr
return {
startToken = startToken,
kind = "if" :: ExprKind,
condition = condition,
block = block,
next = next,
}
end
type BinOpExpr = Expr & { type BinOpExpr = Expr & {
left: Expr, left: Expr,
right: Expr, right: Expr,
@ -236,6 +242,19 @@ end
-- yea -- yea
local function indent(str: string, level: number)
local outputLines = string.split(str, "\n")
for j in outputLines do
-- add indentationLevel
for _ = 1, level do
outputLines[j] = " " .. outputLines[j]
end
end
return table.concat(outputLines, "\n")
end
local function generate(program: { Expr }): string local function generate(program: { Expr }): string
local output = "" local output = ""
@ -245,19 +264,26 @@ local function generate(program: { Expr }): string
i += 1 i += 1
local expr = program[i] local expr = program[i]
local nextExprKind = i + 1 < len and program[i + 1].kind
local kind = expr.kind local kind = expr.kind
if kind == "binop" then if kind == "binop" then
local binop = expr :: BinOpExpr local binop = expr :: BinOpExpr
local value = binop.operator.value local operator = if binop.operator.value == "is"
then "=="
else binop.operator.value
if value == "=" then if operator == "=" then
output ..= "local " output ..= "local "
end end
output ..= generate { binop.left } output ..= generate { binop.left }
output ..= if value == "is" then " == " else ` {value} ` output ..= ` {operator} `
output ..= generate { binop.right } output ..= generate { binop.right }
output ..= "\n"
if operator == "=" then
output ..= "\n"
end
elseif kind == "identifier" then elseif kind == "identifier" then
local identifier = expr :: IdentifierExpr local identifier = expr :: IdentifierExpr
output ..= identifier.startToken.value output ..= identifier.startToken.value
@ -270,52 +296,45 @@ local function generate(program: { Expr }): string
elseif kind == "functioncall" then elseif kind == "functioncall" then
local functioncall = expr :: FunctionCallExpr local functioncall = expr :: FunctionCallExpr
output ..= functioncall.name.value output ..= functioncall.name.value
output ..= "("
output ..= if functioncall.arg.kind == "string" then " " else "("
output ..= generate { functioncall.arg } output ..= generate { functioncall.arg }
output ..= ");\n" output ..= if functioncall.arg.kind == "string" then "" else ")"
if nextExprKind == "if" then
output ..= ";"
end
output ..= "\n"
elseif kind == "if" then elseif kind == "if" then
local ifexpr = expr :: IfExpr local ifexpr = expr :: IfExpr
output ..= "\n(function() if " output ..= "(function()\n"
output ..= generate { ifexpr.condition }
output ..= " then\n"
output ..= generate { ifexpr.block }
if i + 1 < len then local block = ""
local nextExprKind = program[i + 1].kind block ..= "if "
block ..= generate { ifexpr.condition }
block ..= " then\n"
if nextExprKind ~= "elseif" and nextExprKind ~= "else" then block ..= indent(generate { ifexpr.block }, 1)
output ..= "end end)()" block ..= "\n"
end
end
elseif kind == "elseif" then
local elseifexpr = expr :: ElseIfExpr
output ..= "elseif "
output ..= generate { elseifexpr.condition }
output ..= " then\n"
output ..= generate { elseifexpr.block }
if i + 1 < len then block ..= "end"
local nextExprKind = program[i + 1].kind
if nextExprKind ~= "else" then output ..= indent(block, 1)
output ..= "end end)()"
end output ..= "\n"
end output ..= "end)()"
elseif kind == "else" then
local elseexpr = expr :: ElseExpr -- ifexpr.next is an elseifexpr or an elseexpr
output ..= "else\n"
output ..= generate { elseexpr.block }
output ..= "end end)()\n"
elseif kind == "block" then elseif kind == "block" then
local block = expr :: BlockExpr local block = expr :: BlockExpr
local b = 0 local b = 0
while b < #block.expressions - 1 do while b < #block.expressions - 1 do
b += 1 b += 1
output ..= "\t" .. generate { block.expressions[b] } output ..= generate { block.expressions[b] }
end end
output ..= "return " output ..= "return "
output ..= "\t" .. generate { block.expressions[b + 1] } output ..= generate { block.expressions[b + 1] }
output ..= "\n"
elseif kind == "postfix" then elseif kind == "postfix" then
local postfix = expr :: PostfixOpExpr local postfix = expr :: PostfixOpExpr
output ..= generate { postfix.expr } output ..= generate { postfix.expr }
@ -340,6 +359,10 @@ end
local function parse(tokens: { Token }): { Expr } local function parse(tokens: { Token }): { Expr }
local program: { Expr } = {} local program: { Expr } = {}
if #tokens == 0 then
error(colour.red "no tokens to parse")
end
local function addExpr(expr: Expr) local function addExpr(expr: Expr)
table.insert(program, expr) table.insert(program, expr)
end end
@ -356,10 +379,11 @@ local function parse(tokens: { Token }): { Expr }
local blockTokens: { Token } = {} local blockTokens: { Token } = {}
local blockIndent = 0 local blockIndent = 0
-- skip newline at start if #tokens == 0 then
i += 1 error(colour.red "tried to get empty block")
end
while i < len + 1 do -- todo figure out if the + 1 breaks something or not its 5:57 am idck while i < len do -- todo figure out if the + 1 breaks something or not its 5:57 am idck
if tokens[i].kind == "NEWLINE" then if tokens[i].kind == "NEWLINE" then
blockIndent = 0 blockIndent = 0
-- chock next few tokens to see if they're indented -- chock next few tokens to see if they're indented
@ -370,31 +394,37 @@ local function parse(tokens: { Token }): { Expr }
j += 1 j += 1
end end
if blockIndent <= currentIndent then if blockIndent <= currentIndent then
print "block finished"
break break
end end
end end
table.insert(blockTokens, tokens[i]) table.insert(blockTokens, tokens[i])
i += 1 i += 1
end end
if i >= len then
print "welp"
end
if #blockTokens == 0 then
error(colour.red "empty block")
end
print(blockTokens)
return blockTokens return blockTokens
end end
local function getCond(): { Token } local function getCond(): { Token }
local condTokens: { Token } = {} local condTokens: { Token } = {}
-- skip the keyword
i += 1
-- get all tokens until the end of the line -- get all tokens until the end of the line
while i < len and tokens[i + 1].kind ~= "NEWLINE" do while i < len and tokens[i + 1].kind ~= "NEWLINE" do
i += 1 i += 1
table.insert(condTokens, tokens[i]) table.insert(condTokens, tokens[i])
end end
-- skip the newline
i += 1
return condTokens return condTokens
end end
@ -407,7 +437,11 @@ local function parse(tokens: { Token }): { Expr }
end end
local function parseCond(condTokens: { Token }): Expr local function parseCond(condTokens: { Token }): Expr
print("parsing cond", condTokens)
error("bruh")
local cond = parse(condTokens) local cond = parse(condTokens)
if #cond > 1 then if #cond > 1 then
error(colour.red "too many exprs in cond") error(colour.red "too many exprs in cond")
elseif #cond < 1 then elseif #cond < 1 then
@ -423,33 +457,39 @@ local function parse(tokens: { Token }): { Expr }
currentIndent = 0 currentIndent = 0
elseif token.kind == "KEYWORD" then elseif token.kind == "KEYWORD" then
if token.value == "if" then if token.value == "if" then
addExpr( print(i)
IfExpr( local cond = getCond()
token, print(i)
parseCond(getCond()),
BlockExpr(token, parse(getBlock()))
)
)
elseif token.value == "elseif" then
addExpr(
ElseIfExpr(
token,
parseCond(getCond()),
BlockExpr(token, parse(getBlock()))
)
)
elseif token.value == "else" then
-- skip newline
i += 1
local block = getBlock() local block = getBlock()
print("else block", block) local expr = IfExpr(
token,
parseCond(cond),
BlockExpr(token, parse(block))
)
addExpr(expr)
-- elseif token.value == "elseif" then
-- local cond = getCond()
-- -- skip the newline
-- i += 1
-- local block = getBlock()
-- addExpr(
-- ElseIfExpr(
-- token,
-- parseCond(cond),
-- BlockExpr(token, parse(block))
-- )
-- )
-- elseif token.value == "else" then
-- -- skip newline
-- i += 1
addExpr(ElseExpr(token, BlockExpr(token, parse(block)))) -- local block = getBlock()
else -- addExpr(ElseExpr(token, BlockExpr(token, parse(block))))
print(token) -- else
error(colour.red "unknown token value " .. token.value) -- print(token)
-- error(colour.red "unknown token value " .. token.value)
end end
elseif token.kind == "IDENTIFIER" then elseif token.kind == "IDENTIFIER" then
-- identifier is at the start of an expression, it could be: -- identifier is at the start of an expression, it could be:
@ -470,11 +510,12 @@ local function parse(tokens: { Token }): { Expr }
elseif binaryOperators[nextToken.value] then elseif binaryOperators[nextToken.value] then
-- binop -- binop
i = advance i = advance
local cond = getCond()
addExpr(BinOpExpr( addExpr(BinOpExpr(
token, token,
IdentifierExpr(token), IdentifierExpr(token),
-- get condition tokens as rhs -- get condition tokens as rhs
parseCond(getCond()), parseCond(cond),
nextToken nextToken
)) ))
elseif postfixOperators[nextToken.value] then elseif postfixOperators[nextToken.value] then
@ -483,7 +524,8 @@ local function parse(tokens: { Token }): { Expr }
addExpr(PostfixOpExpr(token, IdentifierExpr(token), nextToken)) addExpr(PostfixOpExpr(token, IdentifierExpr(token), nextToken))
else else
i -= 1 -- getCond skips the identifier i -= 1 -- getCond skips the identifier
addExpr(FunctionCallExpr(token, token, parseCond(getCond()))) local cond = getCond()
addExpr(FunctionCallExpr(token, token, parseCond(cond)))
end end
elseif token.kind == "NUMBER" then elseif token.kind == "NUMBER" then
-- number is at the start of an expression, it could be: -- number is at the start of an expression, it could be:
@ -504,11 +546,12 @@ local function parse(tokens: { Token }): { Expr }
else else
-- binop -- binop
i = advance i = advance
local cond = getCond()
addExpr(BinOpExpr( addExpr(BinOpExpr(
token, token,
IdentifierExpr(token), NumberExpr(token),
-- get condition tokens as rhs -- get condition tokens as rhs
parseCond(getCond()), parseCond(cond),
nextToken nextToken
)) ))
end end
@ -533,7 +576,7 @@ local function parse(tokens: { Token }): { Expr }
i = advance i = advance
addExpr(BinOpExpr( addExpr(BinOpExpr(
token, token,
IdentifierExpr(token), StringExpr(token),
-- get condition tokens as rhs -- get condition tokens as rhs
parseCond(getCond()), parseCond(getCond()),
nextToken nextToken

View File

@ -1,20 +1,2 @@
x = 1 ; comments with semicolons
print "x is {x}" ; %x?
print "double x is {2x}"
if x is 142
print "x is equal"
print "yea it is"
elseif x
print "x is truthy" ; whats up
else
print "x is falsy"
x++
print "x is now {x}"
y = if x is 6 y = if x is 6
"yes" print "yes"
else
"no"