Permalink
Browse files

'match' and 'data' macros

  • Loading branch information...
0 parents commit 2caeeafaa32c5780dca8efa6f14d3810394355f5 @bamboo bamboo committed Oct 16, 2007
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>boo-extensions</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>monolipse.core.booBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>monolipse.core.booNature</nature>
+ </natures>
+</projectDescription>
@@ -0,0 +1,18 @@
+Copyright (c) 2007 Rodrigo B. de Oliveira
+
+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.
@@ -0,0 +1,20 @@
+<settings>
+ <language>boo</language>
+ <outputType>library</outputType>
+ <references>
+ <monolipse.core.internal.AssemblySourceReference-Remembrance>
+ <path>/boo-extensions/src/Boo.Adt</path>
+ </monolipse.core.internal.AssemblySourceReference-Remembrance>
+ <monolipse.core.internal.AssemblySourceReference-Remembrance>
+ <path>/boo-extensions/src/Boo.PatternMatching</path>
+ </monolipse.core.internal.AssemblySourceReference-Remembrance>
+ <monolipse.core.internal.GlobalAssemblyCacheReference-Remembrance>
+ <name>nunit.framework</name>
+ <version>2.2.0.0</version>
+ <culture>neutral</culture>
+ <token>96d09a1eb7f44a77</token>
+ </monolipse.core.internal.GlobalAssemblyCacheReference-Remembrance>
+ </references>
+ <outputFolder>/boo-extensions/bin</outputFolder>
+ <additionalOptions></additionalOptions>
+</settings>
@@ -0,0 +1,36 @@
+namespace Boo.Adt.Tests
+
+import NUnit.Framework
+import Boo.Adt
+
+[TestFixture]
+class DataMacroTest:
+
+ [Test]
+ def TestClassHierarchy():
+ type = Expression
+ assert type.IsAbstract
+
+ for type in Const, Add:
+ assert not type.IsAbstract
+ assert not type.IsSealed
+
+ [Test]
+ def TestToString():
+ Assert.AreEqual("Const(42)", Const(42).ToString())
+ Assert.AreEqual("Add(Const(19), Const(22))", Add(Const(19), Const(22)).ToString())
+
+ [Test]
+ def TestEquals():
+ Assert.AreEqual(Const(42), Const(42))
+ assert Const(-1) != Const(42)
+
+ [Test]
+ def TestProperties():
+ Assert.AreEqual(42, Const(42).value)
+
+ def DefineData():
+ # TODO: parser needs to be changed to allow
+ # macros at the top level
+ data Expression = Const(value as int) \
+ | Add(left as Expression, right as Expression)
@@ -0,0 +1,11 @@
+<settings>
+ <language>boo</language>
+ <outputType>library</outputType>
+ <references>
+ <monolipse.core.internal.AssemblySourceReference-Remembrance>
+ <path>/boo-extensions/src/Boo.PatternMatching</path>
+ </monolipse.core.internal.AssemblySourceReference-Remembrance>
+ </references>
+ <outputFolder>/boo-extensions/bin</outputFolder>
+ <additionalOptions></additionalOptions>
+</settings>
@@ -0,0 +1,131 @@
+namespace Boo.Adt
+
+import Boo.Lang.Compiler
+import Boo.Lang.Compiler.Ast
+import Boo.PatternMatching
+
+class DataMacro(AbstractAstMacro):
+
+ override def Expand(node as MacroStatement):
+ DataMacroExpansion(node)
+
+class DataMacroExpansion:
+
+ _module as Module
+ _baseType as TypeReference
+
+ def constructor(node as MacroStatement):
+ match node.Arguments[0]:
+ case BinaryExpression(
+ Operator: BinaryOperatorType.Assign,
+ Left: left,
+ Right: right):
+ _module = enclosingModule(node)
+ _baseType = createBaseType(left)
+ expandDataConstructors(right)
+
+ def enclosingModule(node as Node):
+ return node.GetAncestor(NodeType.Module)
+
+ def createBaseType(node as ReferenceExpression):
+ type = [|
+ abstract class $node:
+ pass
+ |]
+ registerType(type)
+ return SimpleTypeReference(LexicalInfo: node.LexicalInfo, Name: node.Name)
+
+ def expandDataConstructors(node as Expression):
+ match node:
+ case BinaryExpression(Operator: BinaryOperatorType.BitwiseOr,
+ Left: left,
+ Right: right):
+ expandDataConstructors(left)
+ expandDataConstructors(right)
+ case MethodInvocationExpression():
+ expandDataConstructor(node)
+
+ def expandDataConstructor(node as MethodInvocationExpression):
+ match node.Target:
+ case ReferenceExpression(Name: name):
+ type = [|
+ class $name($_baseType):
+ pass
+ |]
+ type.LexicalInfo = node.LexicalInfo
+ for member in membersForArgs(node):
+ type.Members.Add(member)
+ type.Members.Add(toStringForType(type))
+ type.Members.Add(equalsForType(type))
+ type.Members.Add(constructorForInvocation(node))
+ registerType(type)
+
+ def equalsForType(type as TypeDefinition):
+
+ method = [|
+ override def Equals(o):
+ if o is null: return false
+ if GetType() != o.GetType(): return false
+ other as $(type.Name) = o
+ |]
+
+ for field in fields(type):
+ comparison = [|
+ if self.$(field.Name) != other.$(field.Name):
+ return false
+ |]
+ method.Body.Add(comparison)
+
+ method.Body.Add([| return true |])
+ return method
+
+ def toStringForType(type as TypeDefinition):
+ expression = ExpressionInterpolationExpression()
+ items = expression.Expressions
+ items.Add([| $("${type.Name}(") |])
+
+ comma = false
+ for field in fields(type):
+ if comma: items.Add([| ", " |])
+ items.Add([| self.$(field.Name) |])
+ comma = true
+
+ items.Add([| $(")") |])
+ return [|
+ override def ToString():
+ return $expression
+ |]
+
+ def fields(type as TypeDefinition):
+ return f for f as Field in type.Members.Select(NodeType.Field)
+
+ def constructorForInvocation(node as MethodInvocationExpression):
+ ctor = [|
+ def constructor():
+ pass
+ |]
+ for arg in node.Arguments:
+ match arg:
+ case TryCastExpression(
+ Target: ReferenceExpression(Name: name),
+ Type: type):
+ ctor.Parameters.Add(
+ ParameterDeclaration(Name: name, Type: type))
+ ctor.Body.Add([|
+ self.$name = $(ReferenceExpression(name))
+ |])
+ return ctor
+
+ def membersForArgs(node as MethodInvocationExpression):
+ for arg in node.Arguments:
+ yield fieldForArg(arg)
+
+ def fieldForArg(node as TryCastExpression):
+ match node.Target:
+ case ReferenceExpression(Name: name):
+ return [|
+ public final $name as $(node.Type)
+ |]
+
+ def registerType(type as TypeDefinition):
+ _module.Members.Add(type)
@@ -0,0 +1,17 @@
+<settings>
+ <language>boo</language>
+ <outputType>library</outputType>
+ <references>
+ <monolipse.core.internal.GlobalAssemblyCacheReference-Remembrance>
+ <name>nunit.framework</name>
+ <version>2.2.0.0</version>
+ <culture>neutral</culture>
+ <token>96d09a1eb7f44a77</token>
+ </monolipse.core.internal.GlobalAssemblyCacheReference-Remembrance>
+ <monolipse.core.internal.AssemblySourceReference-Remembrance>
+ <path>/boo-extensions/src/Boo.PatternMatching</path>
+ </monolipse.core.internal.AssemblySourceReference-Remembrance>
+ </references>
+ <outputFolder>/boo-extensions/bin</outputFolder>
+ <additionalOptions></additionalOptions>
+</settings>
@@ -0,0 +1,61 @@
+namespace Boo.PatternMatching.Tests
+
+import NUnit.Framework
+import Boo.PatternMatching
+
+class Item:
+ public static final Default = Item(Name: "default")
+
+ [property(Name)] _name = ""
+ [property(Child)] _child as Item
+
+[TestFixture]
+class MatchMacroTest:
+
+ [Test]
+ def TestPropertyPattern():
+ Assert.AreEqual("item foo", itemByName(Item(Name: "foo")))
+ Assert.AreEqual("not foo", itemByName(Item(Name: "not foo")))
+
+ [Test]
+ def TestNestedPropertyPattern():
+ Assert.AreEqual("foo:bar", nestedByName(
+ Item(Name: "foo",
+ Child: Item(Name: "bar"))))
+
+ [Test]
+ def TestQualifiedReference():
+ Assert.AreEqual("default item", itemByQualifiedReference(Item.Default))
+ Assert.AreEqual("foo", itemByQualifiedReference(Item(Name: "foo")))
+
+ [Test]
+ [ExpectedException(MatchError)]
+ def TestMatchErrorOnPropertyPattern():
+ itemByName(42)
+
+ [Test]
+ [ExpectedException(MatchError)]
+ def TestMatchErrorOnNestedPropertyPattern():
+ nestedByName(42)
+
+ def itemByName(o):
+ match o:
+ case Item(Name: "foo"):
+ return "item foo"
+ case Item(Name: name):
+ return name
+
+ def nestedByName(o):
+ match o:
+ case Item(Name: outer, Child: Item(Name: inner)):
+ return "${outer}:${inner}"
+
+ def itemByQualifiedReference(o):
+ match o:
+ case Item(Name: Item.Default.Name):
+ return "default item"
+ case Item(Name: name):
+ return name
+
+
+
@@ -0,0 +1,7 @@
+<settings>
+ <language>boo</language>
+ <outputType>library</outputType>
+ <references/>
+ <outputFolder>/boo-extensions/bin</outputFolder>
+ <additionalOptions></additionalOptions>
+</settings>
Oops, something went wrong.

0 comments on commit 2caeeaf

Please sign in to comment.