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
Port Style compiler to typescript #446
Conversation
…SON file (for orthogonal vectors) in frontend tests. also add orthogonal vectors to registry
… for debugging); all error-checking omitted
…ash but haven't checked correctness of SelEnvs yet
…s tests for substitution-finding helper functions
…stitution code works (with a minor parser/AST incompatibility in RelPred name). TODO write tests for substitution code
… a substance program line + code for converting style exprs/predicates to substance ones. add (passing) test that the compiler finds right substitutions on the LA style program
… as (passing) test
…that form, not IInternalLocalVar) and remove hacks related to it
…genOptProblem (untested)
…in the translation
…lation (except initShape and initProperty)
@wodeni Hey! This is ready for a first review. I updated the description on this PR to reflect the minor cleanup I plan to do. When you review, can you mark the changes you are requesting that are absolutely necessary for this branch, vs. those that are nice-to-have? Given our timeframe, I would prioritize doing the urgent ones first and getting this PR merged so the whole system can be tested. I can queue minor TODOs to be addressed in a more leisurely fashion afterward. Thanks! |
Also thanks for your prev comments! I'll plan to address them soon, unless you want me to wait on any of them? |
Awesome! I’ll do a detailed pass tomorrow morning. My main issue is the overuse of ASTNode types, for which I suggested a few possible solutions above. My last pass was mostly code style stuff. I’ll try to understand the module better in the next pass. Meanwhile, please feel free to address the comments above, mostly importantly the ASTNode thing. Also lmk if there are specific concerns you have, so I can pay close attention to them when I read the code again. |
Cool. Off the top of my head, some concerns are:
Will let you know if others come up, and feel free to ask any qs on slack, I know it's not the world's best documented code right now! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with my second pass. It does seem to be a good one-to-one port. Here are the main comments:
- Error reporting: there are 154 results for
error
in this module. They are (1) reported in inconsistent ways (thrown vs. returned) and (2) only returning a string without any location info. It would be helpful for our error reporting refactor later to know: (a) what types of error there are in Style and (2) for each type of error, what information it will need for reporting the error in any readable and traceable way. I think I'll need your help on both (a) and (b). - Error testing: a reasonable next step of identifying the error types is to write some test cases that trigger these errors.
- Module separation: like my earlier suggestion. Separating the modules along the
#region
line seems to be reasonable. Everything about generating state should probably be in aState
module. - Regarding
AccessPath
: I thought that was the only type we use for both vector and matrix access? Anyway, the way of encoding varying paths is a little messy. I still recommend hashing or finding another representation of paths for cleaner code and better performance. - All requested changes are marked below as
Major
orMinor
}; | ||
|
||
// NOTE: Mutates stmt | ||
const disambiguateSubNode = (env: Env, stmt: ASTNode) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: it's probably better to write this as a pure function.
penrose-web/src/compiler/Style.ts
Outdated
if (header.tag === "Selector") { | ||
// Judgment 7. G |- Sel ok ~> g | ||
const sel: Selector = header; | ||
const selEnv_afterHead = checkDeclPatternsAndMakeEnv(varEnv, initSelEnv(), sel.head.contents); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: camelCase is currently enforced by ESLint. We can do a code style pass after the merge.
const varName: string = bVar.contents.value; | ||
|
||
// TODO(errors) | ||
if (Object.keys(selEnv.sTypeVarMap).includes(varName)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: don't use index type for maps if you are doing a lot of operations on them. Use Map
or immutable Map
because they have better APIs.
penrose-web/src/compiler/Style.ts
Outdated
// Specifically, the Style type for a Substance var needs to be more general. Otherwise, if it's more specific, that's a coercion | ||
// e.g. this is correct: Substance: "SpecialVector `v`"; Style: "Vector `v`" | ||
const declType = toSubstanceType(styType); | ||
if (!isDeclaredSubtype(substanceType, declType, varEnv)) { // COMBAK: Order? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment: the ordering looks correct based on your comment above, but you should add a test case to make sure it's working as intended.
penrose-web/src/compiler/Style.ts
Outdated
// Find a list of substitutions for each selector in the Sty program. (ported from `find_substs_prog`) | ||
export const findSubstsProg = (varEnv: Env, subEnv: SubEnv, subProg: SubProg, | ||
styProg: HeaderBlock[], selEnvs: SelEnv[]): Subst[][] => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment: right, but TS doesn't seem to catch that yet :(. I personally avoid using zip
for this exact reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another way is to use _.compact
afterward.
// Transform stmt into local variable assignment "ANON_$counter = e" and increment counter | ||
if (s.tag === "AnonAssign") { | ||
const stmt: Stmt = { | ||
...s, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment: this is for type annotation, which is optional (indicated by Nothing
).
const ctorNonfloats = propertiesNotOf("FloatV", typ).filter(e => e !== "name"); | ||
const uninitializedProps = ctorNonfloats; | ||
const vs = uninitializedProps.reduce((acc: Path[], curr) => findPropertyUninitialized(name, field, properties, curr, acc), []); | ||
return vs.concat(acc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: TS does exhausiveness check, so you can do else if
or switch
and not handle the unknown case.
penrose-web/src/compiler/Style.ts
Outdated
lbfgsInfo: defaultLbfgsParams, | ||
UOround: -1, | ||
EPround: -1, | ||
} as unknown as Params, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: for now, you can use something like const rng: prng = seedrandom(json.rng, { global: true });
for the generator. We can come back to this later.
// TODO(errors): Maybe fix how warnings are reported? Right now they are put into the "translation" | ||
if (path.tag === "FieldPath") { | ||
const transWithWarnings = deleteField(trans, path.name, path.field); | ||
return Right(transWithWarnings); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: why let
? Looks like const
is better suited for this. BTW these are all caught by ESLint. You can start using it to spot lower-level issues like this.
Thanks for the speedy review @wodeni! I'll address comments in this order:
Aiming to turn it around in a day or so. Questions:
|
There are also some potential errors to handle in functions in Is there a way you would like me to deal with these errors now? Otherwise we can discuss the approach more and then address it in the next round. |
For reviewing large PRs, the VSCode plugin is pretty useful for navigating among functions. Would recommend 😄 .
This decision depends on your desired error reporting behavior: if you do want to catch 1+ errors in the compiler, you will need to accumulate them. It's reasonable to have a
Awesome!
Ideally, you can append new error types to // in errors.d.ts
interface DuplicateName {
tag: "DuplicateName";
name: Identifier;
location: ASTNode;
firstDefined: ASTNode;
}
// in `showError` of Error.ts
case "DuplicateName": {
const { firstDefined, name, location } = error;
return `Name ${name.value} (at ${loc(
location
)}) already exists, first declared at ${loc(firstDefined)}.`;
} In this case, In this PR, I think a type definition, an example error messages, and extra members needed for the error message should be enough for a reasonable first step. I tried to go the extra mile for Substance and Domain (e.g. providing suggestions for, say,
Regardless of how errors are handled internally,
I was referring to the construction of these dummy nodes. I think it's a symptom of overusing AST node types for later stages of compilation (in this case, mostly in generating the translation). The source-related info is there because it's actually designed as an output type for parsers, not synthetic information generated for the translation. Ideally, I think we should eliminate all the dummy node construction code somehow. Possible solutions:
Also, any plan to address the following? I think all the
|
Thanks for the comments! Hmm, the approach you described will take longer than I thought, since it requires formally modeling and categorizing all error types, and requires big code changes to figure out + pass in the relevant info for error reporting. I don't think I can do that in a day. For this branch, I would prefer to return error strings from every function, which are collected and reported in
I guess there are other design requirements we should discuss before picking a solution:
What do you think is the best TS solution for that?
For indexing, I can convert every path to a string using a custom function like |
Sure, that'd be a good first step.
Instead of discarding everything upfront, you could either keep a frozen copy of the AST or have more flexible types that will allow synthetic nodes.
Sure. Perhaps the simplest approach would be to actually create types for these synthetic cases (e.g. type StyleNode = ASTNode | SyntheticNode;
type SyntheticNode = InternalLocalVar | InternalPath | ....
interface InternalPath { // NOTE: _not_ extending `ASTNode`
tag: "InternalPath", // NOTE: all internal paths should have `tag` for compatibility with `ASTNode`!
// ... more data
}
Yeah, sounds good to me. (Hoogle for TS: nothing super mature. I saw this: https://tsearch.io/) |
…` mode) instead of throwing them; clean up some other internal errors
… style-compiler-port
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hypotext and I agreed to address the error-related issues and ASTNode
refactoring in a later PR. This one is good to go!
Description
Related issue/PR: #419 #441
This PR ports the Style compiler to typescript. All past examples work, with the exception of very minor issues listed below.
Implementation strategy and design decisions
This is basically a 1:1 port of the Style compiler from Haskell, with some minor changes made to accommodate the fact that we did the Evaluator in ts first (e.g. use of
insertExpr
in Style compiler) and minor changes in the grammar, as well as minor changes in the functionality of the Domain/Substance toolchain. Errors are dealt with idiosyncratically, usually marked withTODO(errors)
.Done
SEFuncOrValsCons
TODO
s/COMBAK
sChanges to be made in the near future
Style
into modules?Examples with steps to reproduce them
All examples from the previous compiler, on this page, work.
For more documentation, see
compiler/README.md
.Checklist
npm test
npm run docs
and there were no errors when generating the HTML siteOpen questions
Questions that require more discussion or to be addressed in future development: