This repository is a toy project for developers who want to get familiar with the Scala.js IR. It contains the necessary architecture for parsing small expressions, compiling them to IR trees, then link and executes those trees.
It is intentionally not complete. The critical part of compiling a math expression tree into a typed IR tree is left out. That part is meant to be filled in as an exercise to get familiar with the IR.
Please do not look at open Pull Requests of this repository. They will contain ongoing work from other developers and comments from Scala.js authors. Looking at those solutions defeats the purpose of you doing the work to learn!
Open sbt
and run the application with:
> run "5"
which will run the calculator with the expression 5
.
After a bit of logging, this should eventually print the number 5
on the console.
If you try with anything else but a number, as
> run "5 + 4"
You will get a run-time exception, because the compiler cannot handle anything else.
Your task is to fill in the Compiler.compileExpr
method to make it support other kinds of expressions.
There is a small infrastructure for unit-testing your compiler, in the src/test/scala
directory.
You can run the unit tests with
> test
- There are two types in the language:
number
andfunction
. number
is equivalent to aDouble
in Scala.- The parameters of functions are always numbers, and they always return numbers. There is no higher-order function in this language. Functions are therefore only further typed by their arity, i.e., the number of parameters they take.
- Functions can capture
let
bindings and parameters from their enclosing function. Captures can be numbers of functions.
The existing parser recognizes the following language.
[...]
denotes an optional production, and {...}
a zero-to-many production.
expr ::= ifThenElse
| let
| fun
| addSub
ifThenElse ::= 'if' '(' expr ')' addSub 'else' addSub
The condition must be a number. It is "truthy" if it is non-0.
The two branches must have the same type.
let ::= 'let' identifier '=' expr 'in' expr
fun ::= 'fun' '(' [identifier {',' identifier}] ')' '=' '{' expr '}'
addSub ::= divMul { ('+' | '-') divMul }
divMul ::= factor { ('*' | '/') factor }
factor ::= base { '(' [expr {',' expr}] ')' }
Parentheses denote function call.
For calls, `base` must be a function type with the correct arity.
base ::= literalNumber
| identifier
| '(' expr ')'
An identifier can refer to a lexically enclosing `let` binding or
function parameter.
You should implement (parts of) the above language. The recommended order is the following:
- Binary operators
- Let bindings
- if/then/else
- Lambda declaration (without captures) + calls
- Add common math function in the initial environment
(such as
sin
,log
, and others found injava.lang.Math
) - Support captures in lambdas.
While you do this, it is encouraged that you define unit tests for your compiler.
Once you get something working, you can open a pull request with your work, to receive comments. On the pull request discussion, you should act as a contributor would to get their work in the repository. However, in reality, your pull request will not be merged, since that would prevent other developers to go through the same learning process.
It is not necessary to complete the entire language to open a PR. In fact, you can do so as early as you wish to get feedback.
This repository is a learning tool.
For fun, you are free to expand the language, its parser and its compiler, but it is not expected that you do so.
As this repository is meant as a learning tool for developing Scala.js, it follows the same coding style and contributing guidelines. See the master repository at https://github.com/scala-js/scala-js
The code of this repository is distributed under the MIT license:
Copyright (c) 2016 SĂ©bastien Doeraene
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE