Skip to content

Commit

Permalink
Parsing things (expression parsing)
Browse files Browse the repository at this point in the history
Paving the way for the dynamic value system.
  • Loading branch information
exerro committed Nov 16, 2015
1 parent 3b1c607 commit b2ac06e
Show file tree
Hide file tree
Showing 17 changed files with 937 additions and 19 deletions.
3 changes: 2 additions & 1 deletion src/Todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ Graphics
drawSurfaceScaled
drawSurfaceRotated
TermCanvas
getRedirect
getRedirect

12 changes: 0 additions & 12 deletions src/core/DynamicValue.lua

This file was deleted.

69 changes: 69 additions & 0 deletions src/dynamic/BinaryExpression.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

-- @once

-- @ifndef __INCLUDE_sheets
-- @error 'sheets' must be included before including 'sheets.dynamic.BinaryExpression'
-- @endif

-- @print Including sheets.dynamic.BinaryExpression

local tostring = {
[OPERATOR_BINARY_ADD] = "+";
[OPERATOR_BINARY_SUB] = "-";
[OPERATOR_BINARY_MUL] = "*";
[OPERATOR_BINARY_DIV] = "/";
[OPERATOR_BINARY_MOD] = "%";
[OPERATOR_BINARY_POW] = "^";
}

class "BinaryExpression" extends "Expression" {
lvalue = nil;
operator = nil;
rvalue = nil;
}

function BinaryExpression:BinaryExpression( position, lvalue, operator, rvalue )
parameters.checkConstructor( self.class, 4, "position", TokenPosition, position, "lvalue", Expression, lvalue, "operator", "number", operator, "rvalue", Expression, rvalue )

self.position = position
self.lvalue = lvalue
self.operator = operator
self.rvalue = rvalue
end

function BinaryExpression:resolve( env )
local lvalue, rvalue = self.lvalue:resolve( env ), self.rvalue:resolve( env )

if type( lvalue ) ~= "number" then
Exception.throw( ParserException( "expected number lvalue, got " .. type( lvalue ), self.position ) )
elseif type( rvalue ) ~= "number" then
Exception.throw( ParserException( "expected string rvalue, got " .. type( rvalue ), self.position ) )
end

if self.operator == OPERATOR_BINARY_ADD then
return lvalue + rvalue
elseif self.operator == OPERATOR_BINARY_SUB then
return lvalue - rvalue
elseif self.operator == OPERATOR_BINARY_MUL then
return lvalue * rvalue
elseif self.operator == OPERATOR_BINARY_DIV then
return lvalue / rvalue
elseif self.operator == OPERATOR_BINARY_MOD then
return lvalue % rvalue
elseif self.operator == OPERATOR_BINARY_POW then
return lvalue ^ rvalue
end
end

function BinaryExpression:substitute( env )
self.lvalue:substitute( env )
self.rvalue:substitute( env )
end

function BinaryExpression:isConstant()
return self.lvalue:isConstant() and self.rvalue:isConstant()
end

function BinaryExpression:tostring()
return "(" .. self.lvalue:tostring() .. ")" .. tostring[self.operator] .. "(" .. self.rvalue:tostring() .. ")"
end
30 changes: 30 additions & 0 deletions src/dynamic/ConstantExpression.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

-- @once

-- @ifndef __INCLUDE_sheets
-- @error 'sheets' must be included before including 'sheets.dynamic.ConstantExpression'
-- @endif

-- @print Including sheets.dynamic.ConstantExpression

class "ConstantExpression" extends "Expression" {
value = 0;
}

function ConstantExpression:ConstantExpression( position, value )
parameters.checkConstructor( self.class, 1, "position", TokenPosition, position )
self.value = value
self.position = position
end

function ConstantExpression:resolve( env )
return self.value
end

function ConstantExpression:isConstant()
return true
end

function ConstantExpression:tostring()
return tostring( self.value )
end
36 changes: 36 additions & 0 deletions src/dynamic/Expression.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

-- @once

-- @ifndef __INCLUDE_sheets
-- @error 'sheets' must be included before including 'sheets.dynamic.Expression'
-- @endif

-- @print Including sheets.dynamic.Expression

class "Expression" {
position = nil;
}

function Expression:Expression( position )
self.position = position
end

function Expression:resolve( env )

end

function Expression:substitute( env )

end

function Expression:isConstant()

end

function Expression:tostring()

end

function Expression:throw( err )
return Exception.throw( ExpressionException( self.position:tostring() .. ": " .. tostring( err ), 0 ) )
end
25 changes: 25 additions & 0 deletions src/dynamic/ExpressionEnvironment.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

-- @once

-- @ifndef __INCLUDE_sheets
-- @error 'sheets' must be included before including 'sheets.dynamic.ExpressionEnvironment'
-- @endif

-- @print Including sheets.dynamic.ExpressionEnvironment

class "ExpressionEnvironment" {
environment = {};
}

function ExpressionEnvironment:ExpressionEnvironment()
self.environment = {}
end

function ExpressionEnvironment:set( index, value )
self.environment[index] = value
return self
end

function ExpressionEnvironment:get( index )
return self.environment[index]
end
176 changes: 176 additions & 0 deletions src/dynamic/ExpressionParser.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@

-- @once

-- @ifndef __INCLUDE_sheets
-- @error 'sheets' must be included before including 'sheets.dynamic.ExpressionParser'
-- @endif

-- @print Including sheets.dynamic.ExpressionParser

local operators = {
["+"] = true;
["-"] = OPERATOR_UNARY_MINUS;
["*"] = true;
["/"] = true;
["%"] = true;
["^"] = true;
["#"] = OPERATOR_UNARY_LEN;
["!"] = OPERATOR_UNARY_NOT;
}

local binary_operators = {
["+"] = OPERATOR_BINARY_ADD;
["-"] = OPERATOR_BINARY_SUB;
["*"] = OPERATOR_BINARY_MUL;
["/"] = OPERATOR_BINARY_DIV;
["%"] = OPERATOR_BINARY_MOD;
["^"] = OPERATOR_BINARY_POW;
}

local precedence = {
["+"] = 0;
["-"] = 0;
["*"] = 1;
["/"] = 1;
["%"] = 1;
["^"] = 2;
}

class "ExpressionParser" extends "Parser" {
token = 1;
}

function ExpressionParser:consume()
if self:finished() then
return Token( TOKEN_EOF, nil, self.position )
end

if self:matchString() then
return self:consumeString()
elseif self:matchNumber() then
return self:consumeNumber()
elseif self:matchIdentifier() then
return self:consumeIdentifier()
elseif self:matchWhitespace() then
return self:consumeWhitespace()
else
self.character = self.character + 1
if operators[self.text:sub( self.character - 1, self.character - 1 )] then
return Token( TOKEN_OPERATOR, self.text:sub( self.character - 1, self.character - 1 ), self:advancePosition( 1 ) )
end
return Token( TOKEN_SYMBOL, self.text:sub( self.character - 1, self.character - 1 ), self:advancePosition( 1 ) )
end
end

function ExpressionParser:peek( n )
return self.tokens[self.token + ( n or 0 )] or Token( TOKEN_EOF, nil, self.position )
end

function ExpressionParser:next()
self.token = self.token + 1
return self:peek( -1 )
end

function ExpressionParser:test( ... )
return self:peek():matches( ... )
end

function ExpressionParser:parseUnaryLeftOperator()
if self:test( TOKEN_OPERATOR, "-" ) or self:test( TOKEN_OPERATOR, "#" ) or self:test( TOKEN_OPERATOR, "!" ) then
return self:next()
end
end

function ExpressionParser:parseUnaryRightOperator( lvalue )
if self:test( TOKEN_SYMBOL, "(" ) then
-- stuff
elseif self:test( TOKEN_SYMBOL, "." ) then
-- stuff
end
return lvalue
end

function ExpressionParser:parseAtom()
if self:test( TOKEN_STRING ) or self:test( TOKEN_INT ) or self:test( TOKEN_FLOAT ) then
return ConstantExpression( self:peek().position, self:next().value )
elseif self:test( TOKEN_IDENT ) then
return IdentifierExpression( self:peek().position, self:next().value )
else
Exception.throw( ParserException( "expected constant or identifier, got " .. self:peek().token, self:peek().position ) )
end
end

function ExpressionParser:parseNode()
local lops = {}
local node
while true do
local lop = self:parseUnaryLeftOperator()
if lop then
lops[#lops + 1] = lop
else
break
end
end

node = self:parseAtom()

while true do
local rop = self:parseUnaryRightOperator( node )
if rop ~= node then
node = rop
else
break
end
end

for i = #lops, 1, -1 do
node = UnaryLeftExpression( lops[i].position, operators[lops[i].value], node )
end

return node
end

function ExpressionParser:parseBinaryOperator( lvalue )
local operator = self:peek().value
local position = self:next().position
local p = precedence[operator]
local rvalue = self:parseNode()

while true do
if self:test( TOKEN_OPERATOR ) then
local op = self:peek().value
position = self:peek().position

if not precedence[op] then
Exception.throw( ParserException( "expected binary operator, got " .. self:peek().token, self:peek().position ) )
end

if precedence[op] > p then
rvalue = self:parseBinaryOperator( rvalue )
elseif precedence[op] == p then
return self:parseBinaryOperator( BinaryExpression( position, lvalue, binary_operators[operator], rvalue ) )
else
return BinaryExpression( position, lvalue, binary_operators[operator], rvalue )
end
else
return BinaryExpression( position, lvalue, binary_operators[operator], rvalue )
end
end
end

function ExpressionParser:parseExpression()
local lvalue = self:parseNode()

while self:test( TOKEN_OPERATOR ) do
if precedence[self:peek().value] then
lvalue = self:parseBinaryOperator( lvalue )
else
Exception.throw( ParserException( "expected binary operator, got " .. self:peek().token, self:peek().position ) )
end
end
if not self:test( TOKEN_EOF ) then
Exception.throw( ParserException( "unexpected " .. self:peek().token, self:peek().position ) )
end

return lvalue
end
36 changes: 36 additions & 0 deletions src/dynamic/IdentifierExpression.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

-- @once

-- @ifndef __INCLUDE_sheets
-- @error 'sheets' must be included before including 'sheets.dynamic.IdentifierExpression'
-- @endif

-- @print Including sheets.dynamic.IdentifierExpression

class "IdentifierExpression" extends "Expression" {
name = "";
const_value = nil;
}

function IdentifierExpression:IdentifierExpression( position, name )
parameters.checkConstructor( self.class, 2, "position", TokenPosition, position, "name", "string", name )

self.name = name
self.position = position
end

function IdentifierExpression:resolve( env )
return self.const_value or env:get( self.name )
end

function IdentifierExpression:substitute( env )
self.const_value = env:get( self.name )
end

function IdentifierExpression:isConstant()
return self.const_value ~= nil
end

function IdentifierExpression:tostring()
return self.name
end
Loading

0 comments on commit b2ac06e

Please sign in to comment.