Mulang AST spec
In this section, we will get into the technical details of the Mulang AST. It is built around 5 core elements:
- Expressions
- Patterns
- Types
- Equations
- Generators
All the AST elements fall within any of these 5 categories.
Expressions
Expressions are the most important element kind, since contain most of the information of a Mulang program and are always the root element of it. In fact, this implementation does not contain an AST
or Program
datatype - it is instead types as Expression
.
Expression in Mulang model what you will normally spec in a language as a expression, that is something that holds a value and a type. For example, 4 + 5
and [2, 3].toString()
are typical expresion.
However, Mulang extends this concept to most kind of elements in a program, regadless they are have an actual value in the original language. For example, class declarations and while statements are modeled as expression, although in many languages they aren't.
As a rule of thumb if something is or can be represented as an statement, declararion or expression, the it is modeled as Expression
in Mulang AST.
Record
A
Record
represents a record, data or struct declaration, as found in most procedural and functional languages, like the C-likestruct
declaration
Syntax
(Record Identifier)
C Example
struct point {
int x;
int y;
}
(Record "point")
Caveats
Currently, the Record
expression does not hold information about the record contents.
TypeAlias
, TypeSignature
and TypeCast
Mulang AST support for type analysis is quite limited, and it is mostly focused on expressions and declarations analysis. However, for sake of completeness and in order to provide some limited type-information in Mulang AST, TypeAlias
, TypeSignature
and TypeCast
expressions are provided.
See types section for more details.
EntryPoint
Entry point with its name and body. It typically correspond to C-like
main
procedures, orprogram
declarations.
Syntax
(EntryPoint Identifier Expression)
Java Example
public static main(String[] args) {}
(EntryPoint "main" MuNil)
Function
Functional / Imperative programming function declaration. It is is composed by an identifier and one or more equations
Syntax
(Function Identifier [Equation])
C Example
int foo (int bar) {
return bar;
}
Sequence [
TypeSignature "foo" (ParameterizedType ["int"] "int" []),
Function "foo" [
Equation [VariablePattern "bar"]
(UnguardedBody (Return (Reference "bar")))]]
Python Example
def foo():
return 1
(Function "foo" [
(Equation []
(UnguardedBody (Return (MuNumber 1.0))))])
def foo(bar):
return bar
(Function "foo" [
(Equation [VariablePattern "bar"]
(UnguardedBody (Return (Reference "bar"))))])
Procedure
Imperative programming procedure declaration. It is composed by an identifier and one or more equations
Syntax
(Procedure Identifier [Equation])
Method
Object oriented programming method declaration. It is composed by an identifier and one or more equations
Syntax
(Method Identifier [Equation])
Ruby Example
class Bird
def sing!
puts "singing in the dead of night"
end
end
(Class "Bird" Nothing
(Method "sing!" [
(Equation []
(UnguardedBody (Print (MuString "singing in the dead of night"))))]))
Java Example
public class Bird {
public void sing() {
System.out.println("singing in the dead of night");
}
}
(Class "Bird" Nothing
(Method "sing" [
(Equation []
(UnguardedBody (Print (MuString "singing in the dead of night"))))]))
PrimitiveMethod
Declaration of custom primitive operators - also known as operator overriding. See primitive operators
Syntax
(PrimitiveMethod Operator [Equation])
Ruby Example
def ==(other)
end
def hash
end
(Sequence [
(PrimitiveMethod Equal
(Equation [VariablePatten "other"]
(UnguardedBody MuNil))),
(PrimitiveMethod Hash
(Equation []
(UnguardedBody MuNil)))])
Variable
Generic variable declaration, composed by an identifier and an initializer
Syntax
(Variable Identifier Expression)
C Example
int a = 10;
(Sequence [
TypeSignature "a" (SimpleType "int" []),
Variable "a" (MuNumber 10.0)])
JavaScript Example
let x = 1;
(Variable "x" (MuNumber 1))
Assignment
Syntax
(Assignment Identifier Expression)
C Example
m = 3.4;
(Assignment "m" (MuNumber 3.4))
Ruby Example
m = 3.4
(Assignment "m" (MuNumber 3.4))
Attribute
Object oriented programming attribute declaration, composed by an identifier and an initializer
Syntax
(Attribute Identifier Expression)
Java Example
public class Foo {
private int bar = 4;
}
(Class "Foo" Nothing
(Sequence [
(VariableSignature "bar" "int" []),
(Attribute "bar" (MuNumber 4))]))
Object
Object oriented programming global, named object declaration, like Scala's
object
, composed by a name and a body.
Syntax
(Object Identifier Expression)
Example
Class
Object oriented programming global, class declaration, composed by a name, an optional superclass and a body
Syntax
(Class Identifier (Maybe Identifier) Expression)
Ruby Example
class Bird < Animal
end
(Class "Bird" (Just "Animal") MuNil)
Java Examples
public class Bird extends Animal {}
(Class "Bird" (Just "Animal") MuNil)
Enumeration
Imperative named enumeration of values
Syntax
(Enumeration Identifier [Identifier])
Java Example
public enum Fuzzy {
YES, NO, MAYBE
}
(Enumeration "Fuzzy" ["YES", "NO", "MAYBE"])
Interface
Object oriented programming global interface or contract declaration, composed by a name, superinterfaces and a body.
Syntax
(Interface Identifier [Identifier] Expression)
Java Example
public interface Foo extends Bar, Baz {
void foo();
}
(Interface
"Foo"
["Bar", "Baz"]
(TypeSignature "foo" [] "void"))
Rule
Logic programming declaration of rule fact, composed by the rule name, rule arguments, and rule body
Syntax
(Rule Identifier [Pattern] [Expression])
Example
baz(bar) :- foo(bar)
(Rule "baz"
[(LiteralPattern "bar")]
[(Exist "foo"
[(LiteralPattern "bar")])])
Fact
Logic programming declaration of a fact , composed by the fact name and fact arguments
Syntax
(Fact Identifier [Pattern])
Example
foo(bar).
(Fact "foo" [(LiteralPattern "bar")])
Exist
Logic programming existential cuantification / consult
Syntax
(Exist Identifier [Pattern])
Example
Not
Logic programming negation
Syntax
(Not Expression)
Findall
Logic programming findall
Syntax
(Findall Expression Expression Expression)
Forall
Logic programming universal cuantification
Syntax
(Forall Expression Expression)
Reference
Generic variable
Syntax
(Reference Identifier)
C Example
int x = 4;
x
(Sequence [
TypeSignature "x" (SimpleType "int" []),
Variable "x" (MuNumber 4.0),
Reference "x"])
JavaScript Example
const x = 4;
x
(Sequence [
(Variable "x" (MuNumber 4.0),
(Reference "x"))])
Application
Generic, non-curried application of a function or procedure, composed by the applied element itself, and the application arguments
Syntax
(Application Expression [Expression])
Example
Send
Object oriented programming message send, composed by the reciever, selector and arguments
Syntax
(Send Expression Expression [Expression])
Ruby Example
1 + 5
(Send (MuNumber 1) (Reference "+") [MuNumber 5])
New
Object oriented instantiation, composed by the class reference and instantiation arguments
Syntax
(New Identifier [Expression])
Implement
Object oriented instantiation, interface implementation
Syntax
(Implement Identifier)
Include
Object oriented instantiation, mixin inclusion
Syntax
(Include Identifier)
If
Syntax
(If Expression Expression Expression)
Lambda
Syntax
(Lambda [Pattern] Expression)
Return
Syntax
(Return Expression)
While
Imperative programming conditional repetition control structure, composed by a condition and a body
Syntax
(While Expression Expression)
Repeat
Imperative programming fixed repetition control structure, composed by a repetition count expression, and a body
Syntax
(Repeat Expression Expression)
Match
Syntax
(Match Expression [Equation])
Switch
Generic switch expression, composed by the value to switch on, a list of cases and the default
Syntax
(Switch Expression [(Expression, Expression)] Expression)
Try
Generic try expression, composed by a body, a list of exception-handling patterns and statments, and a finally expression
Syntax
(Try Expression [(Pattern, Expression)] Expression)
Raise
Generic raise expression, like a
throw
orraise
statament, composed by the raised expression
Syntax
(Raise Expression)
JavaScript Example
throw 'abc';
(Raise (MuString "abc"))
Print
Generic print expression
Syntax
(Print Expression)
Ruby Example
puts "Hello World"
(Print (MuString "Hello World"))
For
For
s generalices the concept of comprehensions an indexed repetition. With aFor
you can build:
ForComprehension
, when the for expression is a yield. Scala'sfor
comprehensions, Erlang's and Haskell's list comprehensions, and Haskell'sdo-syntaxt
map to it.ForEach
, when the for expression is not a yield. Java'sfor:
, or some scenarios of scala'sfor
map to it.
Syntax
(For [Statment] Expression)
Haskell Example
m = [ f x | x <- [1, 2, 3, 4] ]
(Variable "m"
(For
[(Generator
(VariablePattern "x")
(MuList [(MuNumber 1), (MuNumber 2), (MuNumber 3), (MuNumber 4)]))]
(Yield
(Application (Reference "f") [(Reference "x")]))))
Java Example
for (Integer i : ints) {
System.out.println(i);
}
(For
[(Generator
(VariablePattern "i")
(Reference "ints"))]
(Print (Reference "i")))
ForLoop
ForLoop
represents the imperative programming c-style for loop:
Syntax
(ForLoop Expression Expression Expression Expression)
C Example
for (int i = 0; i < 10; i++) {
foo(i);
}
(ForLoop
(Sequence [
TypeSignature "i" (SimpleType "int" []),
Variable "i" (MuNumber 0.0)])
(Application (Primitive LessThan) [Reference "i",MuNumber 10.0])
(Assignment "i" (Application (Primitive Plus) [Reference "i",MuNumber 1.0]))
(Application (Reference "foo") [Reference "i"])))
JavaScript Example
for (let i = 0; i < 10; i++) {
console.log(i);
}
(ForLoop
(Variable "i" (MuNumber 0.0))
(Application (Reference "<") [Reference "i",MuNumber 10.0])
(Assignment "i" (Application (Reference "+") [Reference "i",MuNumber 1.0]))
(Send (Reference "console") (Reference "log") [Reference "i"]))
Sequence
Generic sequence of statements
Syntax
(Sequence [Expression])
Other
Unrecognized expression, with optional description and body
Syntax
(Other (Maybe Code) (Maybe Expression))
Arrow
Generic arrow - AKA pair or entry - that is typically used to build dictionaries. It corresponds to ruby's, perl's and php's
=>
operator, or ruby's and javascript's:
operator
Syntax
(Arrow Expression Expression)
See MuDict for more details
Self
Object oriented self-reference, like C-like
this
and Smalltalk-derivedself
Syntax
(Self)
None
Used as a placeholder for empty bodies.
Syntax
(None)
Break
Used to break out of flow structure
Syntax
(Break Expression)
Continue
Used to jump over to next flow structure step
Syntax
(Continue Expression)
MuNil
Generic nothing value literal -
nil
,null
,()
orunit
.
Syntax
(MuNil)
MuDict
Generic dictionary - AKA hash, table or map - value literal. Its expressions are normally a sequence of
Arrow
s
Syntax
(MuDict Expression)
Python Example
{'foo': 1}
(MuDict (Arrow (MuString "foo") (MuNumber 1)))
{'foo': 1, 'bar': 2}
(MuDict (Sequence [
(Arrow (MuString "foo") (MuNumber 1)),
(Arrow (MuString "bar") (MuNumber 2))])
MuObject
Object oriented unnamed object literal
Syntax
(MuObject Expression)
JavaScript Example
{}
{foo: 1}
{foo: 1, bar: 2}
(MuObject MuNil)
(MuObject (Attribute "foo" (MuNumber 1)))
(MuObject (Sequence [
(Attribute "foo" (MuNumber 1)),
(Attribute "bar" (MuNumber 2))]))
MuNumber
, MuBool
, MuString
, MuSymbol
and MuChar
Generic number, boolean, string, symbol (atoms) and char literals
Syntax
(MuNumber Double)
(MuBool Bool)
(MuString String)
(MuSymbol String)
(MuChar Char)
Ruby Example
1
true
"hello"
:hello
(Sequence [
(MuNumber 1),
(MuBool True),
(MuString "hello"),
(MuSymbol "hello")])
MuTuple
and MuList
They represent tuples - generic non-uniform fixed-size collection of elements - and lists - generic uniform variable-size collection of elements. Lists typically map to arrays, lists or sequence-like structures.
Syntax
(MuTuple [Expression])
(MuList [Expression])
TestGroup
, Test
and Assert
Generic test framework expressions used to represent unit tests. TestGroup represents a test grouping expression such as
describe
,context
, etc Test represents a test expression such asit
, etc Assert represents a test's assertion, such asassert.equals(...)
, etc. It receives a boolean that represents whether the assertion is negated or not.
Syntax
(TestGroup Expression Expression)
(Test Expression Expression)
(Assert Bool Assertion)
Javascript Example
describe("succ", function() {
it("succ of 3 is 4", function() {
assert.equals(succ(3), 4)
})
})
TestGroup (MuString "succ")
(Test (MuString "succ of 3 is 4")
(Assert False (Equality (Application (Reference "succ") [MuNumber 3.0]) (MuNumber 4.0))))
Python Example
class TestGroup(unittest.TestCase):
def test_succ_of_3_is_4():
self.assertEqual(succ(3), 4)
TestGroup (MuString "TestGroup")
(Test (MuString "test_succ_of_3_is_4")
(Assert False (Equality (Application (Reference "succ") [MuNumber 3.0]) (MuNumber 4.0))))
Assertion
Assertions used within tests to dynamically ascertain the code's validity.
An assertion can be one of:
* Truth
: Assert the truthfulness of a given expression.
* Equality
: Assert the equality of two given expressions.
* Failure
: Assert a given expression fails with a given error.
Syntax
(Truth Expression)
(Equality Expression Expression)
(Failure Expression Expression)
Javascript Examples
assert(true)
Assert False (Truth (MuBool True))
assert.equals(3, 3)
Assert False (Equality (MuNumber 3) (MuNumber 3))
assert.throws(function() { throw('error!') }, 'error!')
Assert False (Failure (Lambda [] (Raise (MuString "error!"))) (MuString "error!"))
Patterns
Patterns are the second most important element of Mulang AST. They represent things that don't hold a value, but are instead used to match values, like
patterns in imperative case
or switch
statements, functional pattern matching in match
or case
expressions, or exception matching in try-catch
or begin-rescue
-like statements in object oriented languages.
VariablePattern
Variable pattern represent a variable match. It corresponds to normal formal parameters in precedural languages, and to simple pattern matching against a free identifier.
Syntax
(VariablePattern String)
JavaScript Example
function foo(x, y) { }
(Function "foo"
[(Equation
[(VariablePattern "x"), (VariablePattern "y")]
(UnguardedBody MuNil))])
LiteralPattern
Literal constant pattern
Syntax
(LiteralPattern String)
Example
InfixApplicationPattern
Infix application pattern like
4:X
Syntax
(InfixApplicationPattern Pattern String Pattern)
Caveats
InfixApplicationPattern
exposes the underying syntax and will be deprecated.
ApplicationPattern
prefix application pattern like
f _
Syntax
(ApplicationPattern String [Pattern])
Example
TuplePattern
tuple pattern like
(3, _)
Syntax
(TuplePattern [Pattern])
Example
ListPattern
list pattern like
[x, y, _]
Syntax
(ListPattern [Pattern])
Example
FunctorPattern
Prolog-like functor pattern, like
f(X, 6)
.
Syntax
(FunctorPattern Identifier [Pattern])
Example
AsPattern
Syntax
(AsPattern Identifier Pattern)
Example
TypePattern
A type pattern, like in exception handling constructs in most object-oriented languages
Syntax
(TypePattern Identifier)
Example
WildcardPattern
Wildcard pattern, typically
_
in functional an logic programming languages.
Syntax
(WildcardPattern)
UnionPattern
Syntax
(UnionPattern [Pattern])
OtherPattern
Other unrecognized pattern
Syntax
(OtherPattern)
Primitive Operators
Primitive operators represent low-level language operations that are well known and common to most languages, usually in the fashion of operators. They are natively supported by mulang.
Absolute
: numericabs
-like absolute operatorAllSatisfy
: collectionall
-like /every
-like operatorAnd
:&&
-like and operatorAnySatisfy
: collectionany
-like /some
-like operatorBackwardComposition
:(g << f)(x) = (g . f)(x) = g(f(x))
operatorBitwiseAnd
: bit-level&
-like and operatorBitwiseLeftShift
: bit-level left<<
-like shift operatorBitwiseOr
: bit-level|
-like or operatorBitwiseRightShift
: bit-level right>>
-like shift operatorBitwiseXor
: bit-level^
-like xor operatorCeil
: numericceil
-like ceiling operatorCollect
: collectionmap
-like operatorCount
: collectioncount
-like operatorDetect
: collectionfind
-like search operatorDetectMax
: collectionmax
-like maximum operatorDetectMin
: collectionmin
-like minumum operatorDivide
: numeric/
operatorEqual
:===
-like equal operatorFlatten
: collectionflatten
-like operatorFloor
: numericceil
-like floor operatorForwardComposition
:(f >> g)(x) = (g . f)(x) = g(f(x))
operatorGather
: collectionflatmap
-like operatorGetAt
: collection[]
-like operatorGreatherOrEqualThan
:>=
operatorGreatherThan
:>
operatorHash
: hashcode operatorInject
: collectionreduce
-like /fold
-like operatorLessOrEqualThan
:<=
operatorLessThan
:<
operatorMax
:max
-like maximum value binary operatorMin
:min
-like minimum value binary operatorMinus
: numeric-
operatorModulo
: numeric%-like
modulo operatorMultiply
: numeric*
operatorNegation
:!
-like not operatorNotEqual
:!==
-like distinct operatorNotSame
: not reference-identical operatorNotSimilar
: not equal-ignoring-type operatorOr
:||
-like or operatorOtherwise
: guard's otherwise operatorPlus
: numeric+
operatorPush
: collectioninsertAtEnd
-like operatorRound
: numericround
-like round operatorSame
: reference-identical operatorSelect
: collectionfilter
-like operatorSetAt
: collection[]=
-like operatorSimilar
: equal-ignoring-type operatorSize
: collectionlength
-like size operator
Types
When processing statically-typed languages, all type-information - regardless we are typing a function, a variable or a class - is represented with the Type
ADT, can be one of:
SimpleType
: composed by a type identifier and zero or type more constraintsParameterizedType
: composed by input type parmaters, an output type, and type constratinsConstrainedType
: composed by just type constraints.OtherType
: an unrecognized type
Type
s can be introduced in the Mulang AST using the following elements:
TypeAlias
A
TypeAlias
represents a synonym for a type, like thetype
declaration in Haskell and Scala or C'stypedef
. It is a typical statically typed functional programming feature.
Syntax
(TypeAlias Identifier Identifier)
Haskell Example
type Point = (Int, Int)
(TypeAlias "Point" "(Int, Int)")
TypeSignature
A
TypeSignature
represents an explicit type annotation for a computation, variable or module, as you can find in Java or Haskell.
Syntax
(TypeSignature Identifier Type)
Haskell Examples
Simple types:
name :: String
(TypeSignature "name" (SimpleType "String" []))
Simple types and constraints:
f :: Num a => a
````
```haskell
(TypeSignature "f" (SimpleType "a" ["Num a"]))
Parameterized types:
elem :: (Eq a, Foldable t) => a -> t a -> Bool
````
```haskell
(TypeSignature "elem" (ParameterizedType ["a", "t a"] "Bool" ["Eq a", "Foldable t"]))
Java Examples
In Java, as in most typed C-like languages, type signature and variable declarations are bound. This means that, for example, a local variable declaration will produce both a TypeSignature
and a Variable
expression.
Variable and attribute types:
String name;
(TypeSignature "name" (SimpleType "String" []))
Method types:
String f() { return null; }
(TypeSignature "f" (ParameterizedType [] "String" []))
Method types with type parameters:
<A> A f() { return null; }
(TypeSignature "f" (ParameterizedType [] "A" ["A"]))
Method types with type parameters and constraints:
<A super B> void f(A a) {}
(TypeSignature "f" (ParameterizedType ["A"] "void" ["A super B"]))
Class or interfaces types:
class A<B extends C, D extends C> { }
(TypeSignature "A" (ConstrainedType ["B extends C", "D extends C"]))
TypeCast
A
TypeCast
represent explictly giving a type to an expression which may have static or dynamic impact on the program. It is aimed to represent type-casts in c-like languages and inline type signatures in functional languages.
Syntax
(TypeCast Expression Type)
Haskell Examples
Simple types:
... = 4 :: Num a => a
(TypeCast (MuNumber 4) (SimpleType "a" ["Num a"]))
Java Examples
Variable and attribute types:
(Integer) 4;
(TypeCast (MuNumber 4) (SimpleType "Integer" []))
(Option<Integer>) something;
(TypeCast (Reference "something") (SimpleType "Option<Integer>" []))
Caveats
The type constraints refer to type-constrained parametrizations that the cast introduces, and not any other kind of constraints the cast uses. That is whay the following Java code:
(Num<A>) something;
produces:
(TypeCast (Reference "something") (SimpleType "Num<A>" []))
instead of:
(TypeCast (Reference "something") (SimpleType "Num" ["A"]))