Check argument list length
This commit is contained in:
parent
43882a3a06
commit
e2d4b76c0b
11
TODO
11
TODO
@ -10,17 +10,8 @@
|
|||||||
- Don't ignore relocations where the symbol is not defined in the symbol table.
|
- Don't ignore relocations where the symbol is not defined in the symbol table.
|
||||||
Report an error about an undefined symbol.
|
Report an error about an undefined symbol.
|
||||||
|
|
||||||
# Name analysis
|
|
||||||
|
|
||||||
- Format error messages.
|
|
||||||
- Return non-zero error code on errors.
|
|
||||||
|
|
||||||
# Register allocation
|
# Register allocation
|
||||||
|
|
||||||
- Each temporary variales gets a tn register where n is the variable index. If
|
- Each temporary variable gets a tn register where n is the variable index. If
|
||||||
there more variables the allocation will fail with out of bounds runtime
|
there more variables the allocation will fail with out of bounds runtime
|
||||||
error. Implement spill over.
|
error. Implement spill over.
|
||||||
|
|
||||||
# Other
|
|
||||||
|
|
||||||
- Type analysis.
|
|
||||||
|
@ -3,42 +3,61 @@ module Language.Elna.Frontend.TypeAnalysis
|
|||||||
, -- Error(..)
|
, -- Error(..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Control.Monad (unless)
|
||||||
|
import Control.Monad.Trans.Class (MonadTrans(..))
|
||||||
|
import Control.Monad.Trans.Except (Except, runExcept, throwE)
|
||||||
|
import Control.Monad.Trans.Reader (ReaderT, runReaderT, withReaderT, ask)
|
||||||
|
import Data.Foldable (traverse_)
|
||||||
|
import qualified Data.Vector as Vector
|
||||||
import qualified Language.Elna.Frontend.AST as AST
|
import qualified Language.Elna.Frontend.AST as AST
|
||||||
import Language.Elna.Frontend.SymbolTable ({-Info(..), ParameterInfo(..), -}SymbolTable)
|
import Language.Elna.Frontend.SymbolTable (Info(..), {-ParameterInfo(..), -}SymbolTable)
|
||||||
|
import qualified Language.Elna.Frontend.SymbolTable as SymbolTable
|
||||||
|
import Language.Elna.Frontend.Types (Type(..), booleanType, intType)
|
||||||
|
import Language.Elna.Location (Identifier(..))
|
||||||
|
|
||||||
typeAnalysis :: SymbolTable -> AST.Program -> () -- Maybe Error
|
typeAnalysis :: SymbolTable -> AST.Program -> Maybe Error
|
||||||
typeAnalysis _globalTable = const () {- either Just (const Nothing)
|
typeAnalysis globalTable = either Just (const Nothing)
|
||||||
. runExcept
|
. runExcept
|
||||||
. flip runReaderT globalTable
|
. flip runReaderT globalTable
|
||||||
. runTypeAnalysis
|
. runTypeAnalysis
|
||||||
. program -}
|
. program
|
||||||
|
|
||||||
{-
|
{-
|
||||||
import Control.Applicative (Alternative(..))
|
import Control.Applicative (Alternative(..))
|
||||||
import Control.Monad.Trans.Except (Except, runExcept, throwE)
|
-}
|
||||||
import Control.Monad.Trans.Reader (ReaderT, asks, runReaderT, withReaderT, ask)
|
|
||||||
import qualified Data.Vector as Vector
|
|
||||||
import Language.Elna.Location (Identifier(..))
|
|
||||||
import qualified Language.Elna.SymbolTable as SymbolTable
|
|
||||||
import Language.Elna.Types (Type(..), booleanType, intType)
|
|
||||||
import Control.Monad.Trans.Class (MonadTrans(..))
|
|
||||||
import Control.Monad (unless, when)
|
|
||||||
import Data.Foldable (traverse_)
|
|
||||||
|
|
||||||
data Error
|
data Error
|
||||||
= ArithmeticExpressionError Type
|
= UnexpectedProcedureInfoError Info
|
||||||
| ComparisonExpressionError Type Type
|
|
||||||
| UnexpectedVariableInfoError Info
|
|
||||||
| UnexpectedProcedureInfoError Info
|
|
||||||
| UndefinedSymbolError Identifier
|
| UndefinedSymbolError Identifier
|
||||||
| InvalidConditionTypeError Type
|
|
||||||
| InvalidAssignmentError Type
|
|
||||||
| ExpectedLvalueError AST.Expression
|
|
||||||
| ParameterCountMismatchError Int Int
|
| ParameterCountMismatchError Int Int
|
||||||
|
| UnexpectedVariableInfoError Info
|
||||||
|
| ArithmeticExpressionError Type
|
||||||
|
| ComparisonExpressionError Type Type
|
||||||
|
| InvalidConditionTypeError Type
|
||||||
|
{- | InvalidAssignmentError Type
|
||||||
|
| ExpectedLvalueError AST.Expression
|
||||||
| ArgumentTypeMismatchError Type Type
|
| ArgumentTypeMismatchError Type Type
|
||||||
| ArrayIndexError Type
|
| ArrayIndexError Type
|
||||||
| ArrayAccessError Type
|
| ArrayAccessError Type -}
|
||||||
deriving (Eq, Show)
|
deriving Eq
|
||||||
|
|
||||||
|
instance Show Error
|
||||||
|
where
|
||||||
|
show (UnexpectedProcedureInfoError info) =
|
||||||
|
"Expected to encounter a procedure, got: " <> show info
|
||||||
|
show (UndefinedSymbolError identifier) =
|
||||||
|
concat ["Symbol \"", show identifier, "\" is not defined"]
|
||||||
|
show (ParameterCountMismatchError parameterCount argumentCount)
|
||||||
|
= "The function was expected to receive " <> show argumentCount
|
||||||
|
<> " arguments, but got " <> show parameterCount
|
||||||
|
show (UnexpectedVariableInfoError info) =
|
||||||
|
"Expected to encounter a variable, got: " <> show info
|
||||||
|
show (ArithmeticExpressionError got) =
|
||||||
|
"Expected an arithmetic expression to be an integer, got: " <> show got
|
||||||
|
show (ComparisonExpressionError lhs rhs)
|
||||||
|
= "Expected an arithmetic expression to be an integer, got \""
|
||||||
|
<> show lhs <> "\" and \"" <> show rhs <> "\""
|
||||||
|
show (InvalidConditionTypeError got) =
|
||||||
|
"Expected a condition to be a boolean, got: " <> show got
|
||||||
|
|
||||||
newtype TypeAnalysis a = TypeAnalysis
|
newtype TypeAnalysis a = TypeAnalysis
|
||||||
{ runTypeAnalysis :: ReaderT SymbolTable (Except Error) a
|
{ runTypeAnalysis :: ReaderT SymbolTable (Except Error) a
|
||||||
@ -61,7 +80,7 @@ program :: AST.Program -> TypeAnalysis ()
|
|||||||
program (AST.Program declarations) = traverse_ declaration declarations
|
program (AST.Program declarations) = traverse_ declaration declarations
|
||||||
|
|
||||||
declaration :: AST.Declaration -> TypeAnalysis ()
|
declaration :: AST.Declaration -> TypeAnalysis ()
|
||||||
declaration (AST.ProcedureDefinition procedureName _ _ body) = do
|
declaration (AST.ProcedureDeclaration procedureName _ _ body) = do
|
||||||
globalTable <- TypeAnalysis ask
|
globalTable <- TypeAnalysis ask
|
||||||
case SymbolTable.lookup procedureName globalTable of
|
case SymbolTable.lookup procedureName globalTable of
|
||||||
Just (ProcedureInfo localTable _) -> TypeAnalysis
|
Just (ProcedureInfo localTable _) -> TypeAnalysis
|
||||||
@ -72,29 +91,29 @@ declaration (AST.ProcedureDefinition procedureName _ _ body) = do
|
|||||||
$ UnexpectedProcedureInfoError anotherInfo
|
$ UnexpectedProcedureInfoError anotherInfo
|
||||||
Nothing -> TypeAnalysis $ lift $ throwE
|
Nothing -> TypeAnalysis $ lift $ throwE
|
||||||
$ UndefinedSymbolError procedureName
|
$ UndefinedSymbolError procedureName
|
||||||
declaration _ = pure ()
|
declaration (AST.TypeDefinition _ _) = pure ()
|
||||||
|
|
||||||
statement :: SymbolTable -> AST.Statement -> TypeAnalysis ()
|
statement :: SymbolTable -> AST.Statement -> TypeAnalysis ()
|
||||||
statement globalTable = \case
|
statement globalTable = \case
|
||||||
AST.EmptyStatement -> pure ()
|
AST.EmptyStatement -> pure ()
|
||||||
AST.AssignmentStatement lhs rhs -> do
|
{- AST.AssignmentStatement lhs rhs -> do
|
||||||
lhsType <- variableAccess globalTable lhs
|
lhsType <- variableAccess globalTable lhs
|
||||||
rhsType <- expression globalTable rhs
|
rhsType <- expression globalTable rhs
|
||||||
unless (lhsType == intType)
|
unless (lhsType == intType)
|
||||||
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError lhsType
|
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError lhsType
|
||||||
unless (rhsType == intType)
|
unless (rhsType == intType)
|
||||||
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError rhsType
|
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError rhsType
|
||||||
|
AST.WhileStatement whileCondition whileStatement -> do
|
||||||
|
conditionType <- condition globalTable whileCondition
|
||||||
|
unless (conditionType == booleanType)
|
||||||
|
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError conditionType
|
||||||
|
statement globalTable whileStatement -}
|
||||||
AST.IfStatement ifCondition ifStatement elseStatement -> do
|
AST.IfStatement ifCondition ifStatement elseStatement -> do
|
||||||
conditionType <- condition globalTable ifCondition
|
conditionType <- condition globalTable ifCondition
|
||||||
unless (conditionType == booleanType)
|
unless (conditionType == booleanType)
|
||||||
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError conditionType
|
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError conditionType
|
||||||
statement globalTable ifStatement
|
statement globalTable ifStatement
|
||||||
maybe (pure ()) (statement globalTable) elseStatement
|
maybe (pure ()) (statement globalTable) elseStatement
|
||||||
AST.WhileStatement whileCondition whileStatement -> do
|
|
||||||
conditionType <- condition globalTable whileCondition
|
|
||||||
unless (conditionType == booleanType)
|
|
||||||
$ TypeAnalysis $ lift $ throwE $ InvalidConditionTypeError conditionType
|
|
||||||
statement globalTable whileStatement
|
|
||||||
AST.CompoundStatement statements -> traverse_ (statement globalTable) statements
|
AST.CompoundStatement statements -> traverse_ (statement globalTable) statements
|
||||||
AST.CallStatement procedureName arguments ->
|
AST.CallStatement procedureName arguments ->
|
||||||
case SymbolTable.lookup procedureName globalTable of
|
case SymbolTable.lookup procedureName globalTable of
|
||||||
@ -110,7 +129,7 @@ statement globalTable = \case
|
|||||||
Nothing -> TypeAnalysis $ lift $ throwE
|
Nothing -> TypeAnalysis $ lift $ throwE
|
||||||
$ UndefinedSymbolError procedureName
|
$ UndefinedSymbolError procedureName
|
||||||
where
|
where
|
||||||
checkArgument ParameterInfo{..} argument = do
|
checkArgument SymbolTable.ParameterInfo{} _argument = pure () {-
|
||||||
argumentType <- expression globalTable argument
|
argumentType <- expression globalTable argument
|
||||||
unless (argumentType == type')
|
unless (argumentType == type')
|
||||||
$ TypeAnalysis $ lift $ throwE $ ArgumentTypeMismatchError type' argumentType
|
$ TypeAnalysis $ lift $ throwE $ ArgumentTypeMismatchError type' argumentType
|
||||||
@ -137,11 +156,11 @@ variableAccess globalTable (AST.ArrayAccess arrayExpression indexExpression) = d
|
|||||||
ArrayType _ baseType -> pure baseType
|
ArrayType _ baseType -> pure baseType
|
||||||
nonArrayType -> TypeAnalysis $ lift $ throwE
|
nonArrayType -> TypeAnalysis $ lift $ throwE
|
||||||
$ ArrayAccessError nonArrayType
|
$ ArrayAccessError nonArrayType
|
||||||
|
-}
|
||||||
expression :: SymbolTable -> AST.Expression -> TypeAnalysis Type
|
expression :: SymbolTable -> AST.Expression -> TypeAnalysis Type
|
||||||
expression globalTable = \case
|
expression globalTable = \case
|
||||||
AST.VariableExpression variableExpression -> do
|
{- AST.VariableExpression variableExpression -> do
|
||||||
variableAccess globalTable variableExpression
|
variableAccess globalTable variableExpression -}
|
||||||
AST.LiteralExpression literal' -> literal literal'
|
AST.LiteralExpression literal' -> literal literal'
|
||||||
AST.NegationExpression negation -> do
|
AST.NegationExpression negation -> do
|
||||||
operandType <- expression globalTable negation
|
operandType <- expression globalTable negation
|
||||||
@ -179,8 +198,6 @@ condition globalTable = \case
|
|||||||
else TypeAnalysis $ lift $ throwE $ ComparisonExpressionError lhsType rhsType
|
else TypeAnalysis $ lift $ throwE $ ComparisonExpressionError lhsType rhsType
|
||||||
|
|
||||||
literal :: AST.Literal -> TypeAnalysis Type
|
literal :: AST.Literal -> TypeAnalysis Type
|
||||||
literal (AST.IntegerLiteral _) = pure intType
|
literal (AST.DecimalLiteral _) = pure intType
|
||||||
literal (AST.HexadecimalLiteral _) = pure intType
|
literal (AST.HexadecimalLiteral _) = pure intType
|
||||||
literal (AST.CharacterLiteral _) = pure intType
|
literal (AST.CharacterLiteral _) = pure intType
|
||||||
literal (AST.BooleanLiteral _) = pure booleanType
|
|
||||||
-}
|
|
||||||
|
48
src/Main.hs
48
src/Main.hs
@ -15,25 +15,39 @@ import Data.Maybe (fromMaybe)
|
|||||||
import System.FilePath (replaceExtension, takeFileName)
|
import System.FilePath (replaceExtension, takeFileName)
|
||||||
import Text.Megaparsec (runParser, errorBundlePretty)
|
import Text.Megaparsec (runParser, errorBundlePretty)
|
||||||
import qualified Data.Text.IO as Text
|
import qualified Data.Text.IO as Text
|
||||||
|
import System.Exit (ExitCode(..), exitWith)
|
||||||
|
import Control.Exception (IOException, catch)
|
||||||
|
|
||||||
|
-- * Error codes
|
||||||
|
--
|
||||||
|
-- 1 - Command line parsing failed and other errors.
|
||||||
|
-- 2 - The input could not be read.
|
||||||
|
-- 3 - Parse error.
|
||||||
|
-- 4 - Name analysis error.
|
||||||
|
-- 5 - Type error.
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = execParser commandLine >>= withCommandLine
|
main = execParser commandLine >>= withCommandLine
|
||||||
where
|
where
|
||||||
withCommandLine CommandLine{..} =
|
withCommandLine CommandLine{..} =
|
||||||
let defaultOutput = flip fromMaybe output
|
let defaultOutputName = replaceExtension (takeFileName input) "o"
|
||||||
$ replaceExtension (takeFileName input) "o"
|
outputName = fromMaybe defaultOutputName output
|
||||||
in Text.readFile input
|
in catch (Text.readFile input) (printAndExit 2 :: IOException -> IO a)
|
||||||
>>= withParsedInput defaultOutput
|
>>= withParsedInput outputName
|
||||||
. runParser programP input
|
. runParser programP input
|
||||||
withParsedInput output (Right program) =
|
withParsedInput output (Right program)
|
||||||
either print (withSymbolTable output program)
|
= either (printAndExit 4) (withSymbolTable output program)
|
||||||
$ nameAnalysis program
|
$ nameAnalysis program
|
||||||
withParsedInput _ (Left errorBundle) = putStrLn
|
withParsedInput _ (Left errorBundle)
|
||||||
$ errorBundlePretty errorBundle
|
= putStrLn (errorBundlePretty errorBundle)
|
||||||
withSymbolTable output program symbolTable =
|
>> exitWith (ExitFailure 3)
|
||||||
let _ = typeAnalysis symbolTable program
|
withSymbolTable output program symbolTable
|
||||||
instructions = generateRiscV
|
| Just typeError <- typeAnalysis symbolTable program =
|
||||||
$ allocate riscVConfiguration
|
printAndExit 5 typeError
|
||||||
$ glue symbolTable program
|
| otherwise =
|
||||||
in elfObject output
|
let instructions = generateRiscV
|
||||||
$ riscv32Elf instructions
|
$ allocate riscVConfiguration
|
||||||
|
$ glue symbolTable program
|
||||||
|
in elfObject output $ riscv32Elf instructions
|
||||||
|
printAndExit :: Show b => forall a. Int -> b -> IO a
|
||||||
|
printAndExit failureCode e = print e >> exitWith (ExitFailure failureCode)
|
||||||
|
Loading…
Reference in New Issue
Block a user