Improvements to if blocks and generation
This commit is contained in:
parent
900f79732a
commit
86892f2c22
261
Script/main.luau
261
Script/main.luau
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue