Visible infix info from imports

This commit is contained in:
2024-10-22 22:08:34 -07:00
parent 19b42d72e5
commit fe323618e7
8 changed files with 79 additions and 60 deletions

View File

@@ -1,10 +1,8 @@
## TODO ## TODO
- [ ] Remember operators from imports - [x] Remember operators from imports
- This one is tricky because we need to parse to get imports, but can't parse expressions until we've loaded imports. - [ ] Default cases for non-primitives (currently gets expanded to all constructors)
- It could be handled by parsing and processing one declaration at a time. We would want this with memoization to do Lean-style incremental builds, but we're not at the LSP stage yet.
- [ ] Default cases (currently gets expanded to all constructors)
- [x] Case for primitives - [x] Case for primitives
- [ ] aoc2023 translation - [ ] aoc2023 translation
- [x] day1 - [x] day1

View File

@@ -1,23 +1,6 @@
module Day1 module Day1
import Lib import Lib
ptype Int
-- TODO fix import of fixity declarations
infixr 4 _::_
infixl 3 _<_
infixl 4 _-_
infixl 4 _+_
infixl 5 _*_
infixl 5 _/_
infixr 0 _$_
-- Code
infixl 7 _._
_._ : {A B C : U} -> (B -> C) -> (A -> B) -> A -> C
(f . g) x = f ( g x)
digits1 : List Char -> List Int digits1 : List Char -> List Int
digits1 Nil = Nil digits1 Nil = Nil

View File

@@ -131,3 +131,8 @@ foldl f acc (x :: xs) = foldl f (f acc x) xs
map : {A B : U} -> (A -> B) -> List A -> List B map : {A B : U} -> (A -> B) -> List A -> List B
map f Nil = Nil map f Nil = Nil
map f (x :: xs) = f x :: map f xs map f (x :: xs) = f x :: map f xs
infixl 7 _._
_._ : {A B C : U} -> (B -> C) -> (A -> B) -> A -> C
(f . g) x = f ( g x)

View File

@@ -90,6 +90,10 @@ parseApp = do
rest <- many pArg rest <- many pArg
pure $ foldl (\a, (icit,fc,b) => RApp fc a b icit) hd rest pure $ foldl (\a, (icit,fc,b) => RApp fc a b icit) hd rest
lookup : String -> List OpDef -> Maybe OpDef
lookup _ [] = Nothing
lookup name (op :: ops) = if op.name == name then Just op else lookup name ops
parseOp : Parser Raw parseOp : Parser Raw
parseOp = parseApp >>= go 0 parseOp = parseApp >>= go 0
where where
@@ -100,7 +104,7 @@ parseOp = parseApp >>= go 0
op <- token Oper op <- token Oper
ops <- getOps ops <- getOps
let op' = "_" ++ op ++ "_" let op' = "_" ++ op ++ "_"
let Just (p,fix) = lookup op' ops let Just (MkOp _ p fix) = lookup op' ops
-- this is eaten, but we need `->` and `:=` to not be an operator to have fatal here -- this is eaten, but we need `->` and `:=` to not be an operator to have fatal here
| Nothing => case op of | Nothing => case op of
-- Location is poor on these because we pull off of the remaining token list... -- Location is poor on these because we pull off of the remaining token list...
@@ -320,12 +324,21 @@ export
parseDecl : Parser Decl parseDecl : Parser Decl
parseDecl = parseMixfix <|> parsePType <|> parsePFunc <|> parseNorm <|> parseData <|> (try $ parseSig) <|> parseDef parseDecl = parseMixfix <|> parsePType <|> parsePFunc <|> parseNorm <|> parseData <|> (try $ parseSig) <|> parseDef
export
parseModHeader : Parser String
parseModHeader = sameLevel (keyword "module") >> uident
export
parseImports : Parser (List Import)
parseImports = manySame $ parseImport
export export
parseMod : Parser Module parseMod : Parser Module
parseMod = do parseMod = do
startBlock $ do
keyword "module" keyword "module"
name <- uident name <- uident
startBlock $ do
imports <- manySame $ parseImport imports <- manySame $ parseImport
decls <- manySame $ parseDecl decls <- manySame $ parseDecl
pure $ MkModule name imports decls pure $ MkModule name imports decls

View File

@@ -49,11 +49,18 @@ showError src (E (line, col) msg) = "ERROR at \{show (line,col)}: \{msg}\n" ++ g
else if line - 3 < l then " " ++ x ++ "\n" ++ go (l + 1) xs else if line - 3 < l then " " ++ x ++ "\n" ++ go (l + 1) xs
else go (l + 1) xs else go (l + 1) xs
public export
record OpDef where
constructor MkOp
name : String
prec : Int
fix : Fixity
-- Result of a parse -- Result of a parse
public export public export
data Result : Type -> Type where data Result : Type -> Type where
OK : a -> (toks : TokenList) -> (com : Bool) -> List (String, Int, Fixity) -> Result a OK : a -> (toks : TokenList) -> (com : Bool) -> List OpDef -> Result a
Fail : Bool -> Error -> (toks : TokenList) -> (com : Bool) -> List (String, Int, Fixity) -> Result a Fail : Bool -> Error -> (toks : TokenList) -> (com : Bool) -> List OpDef -> Result a
export export
Functor Result where Functor Result where
@@ -74,10 +81,10 @@ Functor Result where
-- This is a Reader in FC, a State in Operators, Commit flag, TokenList -- This is a Reader in FC, a State in Operators, Commit flag, TokenList
export export
data Parser a = P (TokenList -> Bool -> List (String, Int, Fixity) -> (lc : FC) -> Result a) data Parser a = P (TokenList -> Bool -> List OpDef -> (lc : FC) -> Result a)
export export
runP : Parser a -> TokenList -> Bool -> List (String, Int, Fixity) -> FC -> Result a runP : Parser a -> TokenList -> Bool -> List OpDef -> FC -> Result a
runP (P f) = f runP (P f) = f
error : TokenList -> String -> Error error : TokenList -> String -> Error
@@ -91,6 +98,13 @@ parse pa toks = case runP pa toks False [] (-1,-1) of
OK a [] _ _ => Right a OK a [] _ _ => Right a
OK a ts _ _ => Left (error ts "Extra toks") OK a ts _ _ => Left (error ts "Extra toks")
||| Intended for parsing a top level declaration
export
partialParse : Parser a -> List OpDef -> TokenList -> Either Error (a, List OpDef, TokenList)
partialParse pa ops toks = case runP pa toks False ops (0,0) of
Fail fatal err toks com ops => Left err
OK a ts _ ops => Right (a,ops,ts)
-- I think I want to drop the typeclasses for v1 -- I think I want to drop the typeclasses for v1
export export
@@ -108,13 +122,13 @@ fatal : String -> Parser a
fatal msg = P $ \toks,com,ops,col => Fail True (error toks msg) toks com ops fatal msg = P $ \toks,com,ops,col => Fail True (error toks msg) toks com ops
export export
getOps : Parser (List (String, Int, Fixity)) getOps : Parser (List OpDef)
getOps = P $ \ toks, com, ops, col => OK ops toks com ops getOps = P $ \ toks, com, ops, col => OK ops toks com ops
export export
addOp : String -> Int -> Fixity -> Parser () addOp : String -> Int -> Fixity -> Parser ()
addOp nm prec fix = P $ \ toks, com, ops, col => addOp nm prec fix = P $ \ toks, com, ops, col =>
OK () toks com ((nm, prec, fix) :: ops) OK () toks com ((MkOp nm prec fix) :: ops)
export export
Functor Parser where Functor Parser where

View File

@@ -19,11 +19,11 @@ lookup nm top = go top.defs
export export
covering covering
Show TopContext where Show TopContext where
show (MkTop defs metas _ _ _) = "\nContext:\n [\{ joinBy "\n" $ map show defs}]" show (MkTop defs metas _ _ _ _) = "\nContext:\n [\{ joinBy "\n" $ map show defs}]"
public export public export
empty : HasIO m => m TopContext empty : HasIO m => m TopContext
empty = pure $ MkTop [] !(newIORef (MC [] 0)) False !(newIORef []) [] empty = pure $ MkTop [] !(newIORef (MC [] 0)) False !(newIORef []) [] []
||| set or replace def. probably need to check types and Axiom on replace ||| set or replace def. probably need to check types and Axiom on replace
public export public export

View File

@@ -366,7 +366,7 @@ record TopContext where
errors : IORef (List Error) errors : IORef (List Error)
||| loaded modules ||| loaded modules
loaded : List String loaded : List String
ops : List OpDef
-- we'll use this for typechecking, but need to keep a TopContext around too. -- we'll use this for typechecking, but need to keep a TopContext around too.
public export public export

View File

@@ -38,7 +38,6 @@ dumpContext top = do
go [] = pure () go [] = pure ()
go (x :: xs) = putStrLn " \{show x}" >> go xs go (x :: xs) = putStrLn " \{show x}" >> go xs
writeSource : String -> M () writeSource : String -> M ()
writeSource fn = do writeSource fn = do
docs <- compile docs <- compile
@@ -50,50 +49,57 @@ writeSource fn = do
Right _ <- chmodRaw fn 493 | Left err => fail (show err) Right _ <- chmodRaw fn 493 | Left err => fail (show err)
pure () pure ()
parseFile : String -> M (String,Module) ||| New style loader, one def at a time
parseFile fn = do processModule : String -> List String -> String -> M String
processModule base stk name = do
top <- get
let False := elem name top.loaded | _ => pure ""
modify { loaded $= (name::) }
let fn = base ++ "/" ++ name ++ ".newt"
Right src <- readFile $ fn Right src <- readFile $ fn
| Left err => fail (show err) | Left err => fail (show err)
let toks = tokenise src let toks = tokenise src
let Right res = parse parseMod toks
| Left y => fail (showError src y)
pure (src, res)
loadModule : String -> List String -> String -> M () let Right (modName, ops, toks) := partialParse parseModHeader top.ops toks
loadModule base stk name = do | Left err => fail (showError src err)
top <- get
-- already loaded?
let False := elem name top.loaded | _ => pure () putStrLn "module \{modName}"
modify { loaded $= (name::) } let True = name == modName
let fn = base ++ "/" ++ name ++ ".newt" | _ => fail "ERROR at (0, 0): module name \{show modName} doesn't match file name \{show fn}"
(src, res) <- parseFile fn
putStrLn "module \{res.name}" let Right (imports, ops, toks) := partialParse parseImports ops toks
let True = name == res.name | Left err => fail (showError src err)
| _ => fail "ERROR at (0, 0): module name \{show res.name} doesn't match file name \{show fn}"
-- TODO separate imports and detect loops / redundant for_ imports $ \ (MkImport fc name') => do
for_ res.imports $ \ (MkImport fc name') => do
-- we could use `fc` if it had a filename in it -- we could use `fc` if it had a filename in it
when (name' `elem` stk) $ error emptyFC "import loop \{show name} -> \{show name'}"
loadModule base (name :: stk) name'
-- TODO Lift the error exit, so import errors can get a FC in current file when (name' `elem` stk) $ error emptyFC "import loop \{show name} -> \{show name'}"
processModule base (name :: stk) name'
top <- get
let Right (decls, ops, toks) := partialParse (manySame parseDecl) top.ops toks
| Left err => fail (showError src err)
let [] := toks | (x :: xs) => fail "extra toks" -- FIXME FC from xs
modify { ops := ops }
putStrLn "process Decls" putStrLn "process Decls"
Right _ <- tryError $ traverse_ processDecl (collectDecl res.decls) Right _ <- tryError $ traverse_ processDecl (collectDecl decls)
| Left y => fail (showError src y) | Left y => fail (showError src y)
pure () pure src
processFile : String -> M () processFile : String -> M ()
processFile fn = do processFile fn = do
putStrLn "*** Process \{fn}" putStrLn "*** Process \{fn}"
(src, res) <- parseFile fn
putStrLn "module \{res.name}"
let parts = splitPath fn let parts = splitPath fn
let file = fromMaybe "" $ last' parts let file = fromMaybe "" $ last' parts
let dir = fromMaybe "./" $ parent fn let dir = fromMaybe "./" $ parent fn
let (name,ext) = splitFileName (fromMaybe "" $ last' parts) let (name,ext) = splitFileName (fromMaybe "" $ last' parts)
putStrLn "\{show dir} \{show name} \{show ext}" putStrLn "\{show dir} \{show name} \{show ext}"
loadModule dir [] name
src <- processModule dir [] name
top <- get top <- get
-- dumpContext top -- dumpContext top