diff --git a/src/main/wacc/Main.scala b/src/main/wacc/Main.scala index d964657..3d16c33 100644 --- a/src/main/wacc/Main.scala +++ b/src/main/wacc/Main.scala @@ -72,7 +72,7 @@ def frontend( ): Either[NonEmptyList[Error], microWacc.Program] = parser.parse(contents) match { case Failure(msg) => Left(NonEmptyList.one(Error.SyntaxError(msg))) - case Success(prog) => + case Success(ast.PartialProgram(_, prog)) => given errors: mutable.Builder[Error, List[Error]] = List.newBuilder val (names, funcs) = renamer.rename(prog) diff --git a/src/main/wacc/frontend/ast.scala b/src/main/wacc/frontend/ast.scala index 9b14b13..e331e2d 100644 --- a/src/main/wacc/frontend/ast.scala +++ b/src/main/wacc/frontend/ast.scala @@ -131,6 +131,18 @@ object ast { /* ============================ PROGRAM STRUCTURE ============================ */ + case class ImportedFunc(sourceName: Ident, importName: Ident)(val pos: Position) + object ImportedFunc extends ParserBridgePos2[Ident, Option[Ident], ImportedFunc] { + def apply(a: Ident, b: Option[Ident])(pos: Position): ImportedFunc = + new ImportedFunc(a, b.getOrElse(a))(pos) + } + + case class Import(source: StrLiter, funcs: NonEmptyList[ImportedFunc])(val pos: Position) + object Import extends ParserBridgePos2[StrLiter, NonEmptyList[ImportedFunc], Import] + + case class PartialProgram(imports: List[Import], self: Program)(val pos: Position) + object PartialProgram extends ParserBridgePos2[List[Import], Program, PartialProgram] + case class Program(funcs: List[FuncDecl], main: NonEmptyList[Stmt])(val pos: Position) object Program extends ParserBridgePos2[List[FuncDecl], NonEmptyList[Stmt], Program] diff --git a/src/main/wacc/frontend/parser.scala b/src/main/wacc/frontend/parser.scala index e798284..9f3fa40 100644 --- a/src/main/wacc/frontend/parser.scala +++ b/src/main/wacc/frontend/parser.scala @@ -3,12 +3,12 @@ package wacc import parsley.Result import parsley.Parsley import parsley.Parsley.{atomic, many, notFollowedBy, pure, unit} -import parsley.combinator.{countSome, sepBy} +import parsley.combinator.{countSome, sepBy, option} import parsley.expr.{precedence, SOps, InfixL, InfixN, InfixR, Prefix, Atoms} import parsley.errors.combinator._ import parsley.errors.patterns.VerifiedErrors import parsley.syntax.zipped._ -import parsley.cats.combinator.{some} +import parsley.cats.combinator.{some, sepBy1} import cats.data.NonEmptyList import parsley.errors.DefaultErrorBuilder import parsley.errors.ErrorBuilder @@ -52,8 +52,8 @@ object parser { implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken { def tokens = errTokens } - def parse(input: String): Result[String, Program] = parser.parse(input) - private val parser = lexer.fully(``) + def parse(input: String): Result[String, PartialProgram] = parser.parse(input) + private val parser = lexer.fully(``) // Expressions private lazy val ``: Parsley[Expr] = precedence { @@ -87,11 +87,12 @@ object parser { IntLiter(integer).label("integer literal"), BoolLiter(("true" as true) | ("false" as false)).label("boolean literal"), CharLiter(charLit).label("character literal"), - StrLiter(stringLit).label("string literal"), + ``.label("string literal"), PairLiter from "null", ``, Parens("(" ~> `` <~ ")") ) + private val `` = StrLiter(stringLit) private val `` = Ident(ident) | some("*" | "&").verifiedExplain("pointer operators are not allowed") private lazy val `` = @@ -127,6 +128,19 @@ object parser { invalid syntax check, this only happens at most once per program so this is not a major concern. */ + private lazy val `` = PartialProgram( + many(``), + `` + ) + private lazy val `` = Import( + "import" ~> ``, + "(" ~> sepBy1(``, ",") <~ ")" + ) + private lazy val `` = ``.label("import file name") + private lazy val `` = ImportedFunc( + ``.label("imported function name"), + option("as" ~> ``).label("imported function alias") + ) private lazy val `` = Program( "begin" ~> ( many(