Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type check input #165

Merged
merged 4 commits into from Nov 9, 2020
Merged

Type check input #165

merged 4 commits into from Nov 9, 2020

Conversation

alexgrejuc
Copy link
Contributor

@alexgrejuc alexgrejuc commented Nov 5, 2020

This, in combination with your editor changes, is good to merge so that we have better handling of input for users. Fixes #165.

src/API/Run.hs Outdated

-- this is bad. We grab the last Val off the buffer, which has not been typechecked
-- then we do: Val => String => Expr so that we can type check it
-- it would be much better to receive it as a Maybe Expr separate from the buffer
Copy link
Contributor Author

@alexgrejuc alexgrejuc Nov 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we have now works, but is sketchy. We can discuss my proposed change for a further change in the near future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sketchy how so?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above is the short version. It would be much easier to explain in full detail over a Discord chat, which we should do soon!

@@ -217,6 +216,19 @@ reservedOp = P.reservedOp lexer
comma :: ParsecT String u Identity String
comma = P.comma lexer

-- | A parser for a literal expression
literal :: Parser (Expr SourcePos)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide that only literals should be allowed, we can use this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

@@ -192,10 +193,21 @@ tc g = case tc' g of
(_e, ls) -> let l = lefts ls in
Tc (length l == 0) _e l (rights ls ++ types _e)

-- | Typecheck a game, and produce a tuple of an environment, with a list of errors and/or successfully typechecked names
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shortened a long line

@alexgrejuc alexgrejuc mentioned this pull request Nov 5, 2020
Copy link
Contributor

@montymxb montymxb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit concerned that the parsing for literals will allow malformed tuples. If you could add a test to verify this is not the case that would be good. Also I had a punctuation thing, and a question, beyond that the rest seems okay for an initial work.

I understand we'll be making additional changes from this point onwards, so some of this may be irrelevant, so the addition of some lit tests would be the minimum to add here.

src/API/Run.hs Outdated

-- this is bad. We grab the last Val off the buffer, which has not been typechecked
-- then we do: Val => String => Expr so that we can type check it
-- it would be much better to receive it as a Maybe Expr separate from the buffer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sketchy how so?

@@ -21,6 +21,7 @@ data Error = Error {

-- Note: the error code functionality works, but only for type errors so they are not displayed
instance Show Error where
show (Error (TE e@(InputMismatch _ _ _)) _ _) = show e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

@@ -34,4 +35,5 @@ instance Show TypeError where
show (BadApp n e) = "Could not apply " ++ n ++ " to " ++ show e ++ "; it is not a function."
show (Dereff n _t) = "Could not dereference the function " ++ n ++ " with type " ++ show _t ++ ". Maybe you forgot to give it arguments."
show (Uninitialized n) = "Incomplete initialization of Board " ++ quote n
show (SigBadFeq n sig f) = quote (n ++ " : " ++ show sig) ++ " cannot be defined with the function equation\n\t" ++ show f
show (SigBadFeq n sig f) = quote (n ++ " : " ++ show sig) ++ " cannot be defined with the function equation\n\t" ++ show f
show (InputMismatch act xp e) = "Got type " ++ show act ++ " but expected type " ++ show xp ++ " from input:\n\t" ++ show e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small punctuation nit, can add a comma between got & expected. Got type Int, but expected...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch; I will fix it.

@@ -217,6 +216,19 @@ reservedOp = P.reservedOp lexer
comma :: ParsecT String u Identity String
comma = P.comma lexer

-- | A parser for a literal expression
literal :: Parser (Expr SourcePos)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

<|>
S <$> capIdentifier
<|>
Tuple <$> parens ((:) <$> (lexeme literal <* lexeme comma) <*> commaSep literal)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has the capacity to match (1,) if I am reading this correctly. Maybe it will be caught elsewhere, but by definition our tuples are a pair or more in BoGL. We could add

... (lexeme literal <* lexeme comma <* lexeme literal) <*> try $ lexeme comma *> commaSep literal

Or something of that form, basically guarantee a tuple to parse only if it has minimum two elements, and potentially look for others preceded by an additional comma.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test against this would be revealing if this is a problem in the first place actually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Good catch.

isInputType ie = do
et <- exprtypeE ie
it <- getInput
if et <= it then return () else inputmismatch $ Plain et
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

Copy link
Contributor

@montymxb montymxb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes currently up are good and look mergable, but I'll leave this as a comment if you choose to add on the extra changes for a buffer of [String] instead of [Val], whenever you have some time later this weekend or during next week.

@@ -196,13 +196,18 @@ gameIdentifier = capIdentifier
capIdentifier :: ParsecT String u Identity [Char]
capIdentifier = lookAhead upper *> identifier

-- | Comma separated values, 2 or more
commaSep2 :: ParsecT String u Identity a -> ParsecT String u Identity [a]
commaSep2 p = (:) <$> (lexeme p <* lexeme comma) <*> commaSep1 p
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome 👍

True $
checkAllParsePass literal lits)
where
lits = ["1", "True", "False", "-1", "+1", "A", "(((40, 2), Nested, Tuple), 0)",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests look good

@alexgrejuc
Copy link
Contributor Author

The one problem is that the API tests are not comprehensive, however, I have already done quite a bit in this PR. In my opinion, fine-tuning the API and testing it is a significant amount of work and a totally separate issue. I did add some preliminary tests and I made it easier to test by making the handler functions pure.

@@ -144,8 +138,8 @@ instance Show SpielResponse where
show (SpielTypeHole m _ _) = show m
-- show a fallback error, such as reading a bad-file
show (SpielError m) = show m
show x = show x
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grrrrrr, I lost more time than I would like to admit due to this line.

show x = show x

show (SpielTypeError e) = show e
show _ = "unused SpielResponse" -- todo: clean these out
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not want to write cases for unused responses, but I also did not want to remove them in this change set for fear of changing too much at once.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good call. This is a certain unspoken limit before the PR should just be split into another PR haha

import Runtime.Monad
import Runtime.Monad (Buffer, emptyEnv)

import Control.Monad(liftM, ap)

-- | Runs BoGL code from raw text with the given commands
-- utilizes parsePreludeAndGameText to parse the code directly,
-- without reading it from a file first
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function was unnecessarily in the IO monad! I pulled it out so that it is easier to test.

@@ -10,49 +10,80 @@ Holds the routines for parsing and interpreting a BoGL Prelude and Game file.

module API.Run (_runCodeWithCommands) where

import API.JSONData
import API.JSONData (SpielResponse(..), SpielCommand(..), SpielResponses, spielParseError)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file still needs quite a bit of cleaning up, but I had to let it go eventually. We can do some more work to polish the API later and do it then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to clean things up once we've taken care of whatever comes up at this upcoming meeting. In addition, it would probably be good to make several smaller changes in separate PRs. Everything that is changed there will go live, and the more we change the more likely we are to introduce a bug. Small changes will make that easier to track down when they occur.

@@ -94,9 +94,9 @@ boardt = Plain boardxt
boardxt :: Xtype
boardxt = bnestx Board

-- | Nest a Btype as a Type
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused and it caused a lot of issues with shadowing

@@ -540,9 +557,8 @@ parseGameFromText :: String -> String -> ([Maybe (ValDef SourcePos)], ParState)
parseGameFromText prog fileName pr = parseWithState (snd pr) (parseGame (catMaybes (fst pr))) fileName prog

-- | Parse a prelude and game from text directly, without a file
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was no reason for this to be in IO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I added the IO stuff in when we were first writing these out. I believe that was because we were still reading & writing from files instead of parsing the responses directly. Seems it was never re-addressed when we phased that out.

True $
checkAllParsePass literal lits)
where
lits = ["1", " 1", "1 ", "True", "False", "-1", "+1", "A", "(((40, 2), Nested, Tuple), 0)",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 is a unary plus, just like -1 is a unary minus. Did you know that 1 + + 1 ==> 1 + (+1) is a valid BoGL program? Perhaps it could be removed, but that requires messing around with the lexer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I had no clue, a little bit surprised actually. We can bring this up with Martin, but this seems like a very small concern for the moment.

@alexgrejuc
Copy link
Contributor Author

One final note: don't squash these commits if you merge the PR! They are isolated units and it can be helpful to have them in the history for bug-tracking.

Copy link
Contributor

@montymxb montymxb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, merging this in.

@@ -10,49 +10,80 @@ Holds the routines for parsing and interpreting a BoGL Prelude and Game file.

module API.Run (_runCodeWithCommands) where

import API.JSONData
import API.JSONData (SpielResponse(..), SpielCommand(..), SpielResponses, spielParseError)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to clean things up once we've taken care of whatever comes up at this upcoming meeting. In addition, it would probably be good to make several smaller changes in separate PRs. Everything that is changed there will go live, and the more we change the more likely we are to introduce a bug. Small changes will make that easier to track down when they occur.

@@ -540,9 +557,8 @@ parseGameFromText :: String -> String -> ([Maybe (ValDef SourcePos)], ParState)
parseGameFromText prog fileName pr = parseWithState (snd pr) (parseGame (catMaybes (fst pr))) fileName prog

-- | Parse a prelude and game from text directly, without a file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I added the IO stuff in when we were first writing these out. I believe that was because we were still reading & writing from files instead of parsing the responses directly. Seems it was never re-addressed when we phased that out.

-- unused
--safeLast :: [a] -> Maybe a
--safeLast [] = Nothing
--safeLast xs = Just $ last xs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is already way too big so I won't ask for it here, but this is an empty file now. In the next PR we should remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think it is worth keeping. I am certain we will have (if we do not already have) functions that are generally useful and should not be contained to a specific module. Keeping this file makes it more likely that a function like that will end up in the proper location rather than tucked away in another module. That is exactly the situation we had with the string utility functions, whose functionality was often being duplicated.

True $
checkAllParsePass literal lits)
where
lits = ["1", " 1", "1 ", "True", "False", "-1", "+1", "A", "(((40, 2), Nested, Tuple), 0)",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I had no clue, a little bit surprised actually. We can bring this up with Martin, but this seems like a very small concern for the moment.

@montymxb montymxb merged commit 560c952 into master Nov 9, 2020
@alexgrejuc alexgrejuc deleted the type-check-input branch November 11, 2020 06:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants