Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Added facilities for LexicalInfo. #5

Closed
wants to merge 6 commits into from

1 participant

Maksym Trushyn
Maksym Trushyn

I added facilities for LexicalInfo. I hope I'm moving in the right direction.
Also OMetaInputWithMemo is improved as it is used more actively now.

Maksym Trushyn MaximTrushin closed this November 14, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 6 unique commits by 1 author.

Aug 24, 2011
Maksym Trushyn Fixed logic for OMetaInputWithMemo . a4d3c0a
Oct 28, 2011
Maksym Trushyn Added facilities for LexicalInfo.
Improvements for OMetaInputWithMemo.
d75b93b
Nov 02, 2011
Maksym Trushyn Removed missing app.config file because it is not generated automatic…
…ally by nant.
e17557c
Maksym Trushyn Changed target .Net version.
Boo references are changed to relative paths.
Removing version of NUnit in references.
a7da10f
Maksym Trushyn Added obj folder to gitignore. a4d3809
Nov 03, 2011
Maksym Trushyn Saving start of a token in every token.
Using the saved value to track SourceLocation in some scenarios.
9305921
This page is out of date. Refresh to see the latest.
1  .gitignore
@@ -4,3 +4,4 @@ build.properties
4 4
 *.pidb
5 5
 *.userprefs
6 6
 test-results
  7
+obj
4  src/Boo.Adt/Boo.Adt.booproj
... ...
@@ -1,4 +1,4 @@
1  
-<?xml version="1.0" encoding="utf-8"?>
  1
+<?xml version="1.0" encoding="utf-8"?>
2 2
 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3
   <PropertyGroup>
4 4
     <ProjectGuid>{18AF07E6-C62E-4CDC-8F58-5A0F9A872F7F}</ProjectGuid>
@@ -7,7 +7,7 @@
7 7
     <OutputType>Library</OutputType>
8 8
     <RootNamespace>Boo.Adt</RootNamespace>
9 9
     <AssemblyName>Boo.Adt</AssemblyName>
10  
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  10
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
11 11
     <ProductVersion>9.0.21022</ProductVersion>
12 12
     <SchemaVersion>2.0</SchemaVersion>
13 13
     <UsePartialTypes>false</UsePartialTypes>
32  src/Boo.OMeta.Parser.Tests/BooParserTestFixture.boo
@@ -22,7 +22,37 @@ partial class BooParserTestFixture:
22 22
 				assert m.Documentation is not null
23 23
 				Assert.AreEqual(normalize(m.Documentation), normalize(m.ToCodeString()))
24 24
 				assert input.IsEmpty, input.ToString()
25  
-						
  25
+
  26
+
  27
+	[Test]
  28
+	def TestEndSourceLocationForInlineClosures():
  29
+		code = """foo = { a = 3;
  30
+return a; }"""
  31
+		EnsureClosureEndSourceLocation(code, 2, 11)
  32
+		
  33
+		
  34
+	[Test]
  35
+	def TestEndSourceLocationForBlockClosures():
  36
+		code = """
  37
+foo = def():
  38
+    return a
  39
+"""
  40
+		EnsureClosureEndSourceLocation(code, 3, 13)
  41
+		
  42
+
  43
+	def EnsureClosureEndSourceLocation(code as string, line as int, column as int):		
  44
+		parser = BooParser()
  45
+		
  46
+		match parser.module(code):
  47
+			case SuccessfulMatch(Input: input, Value: m=Module()):
  48
+				assert m is not null
  49
+				assert input.IsEmpty, input.ToString()
  50
+				e = (m.Globals.Statements[0] as ExpressionStatement).Expression
  51
+				cbe = (e as BinaryExpression).Right as BlockExpression
  52
+				esl = cbe.Body.EndSourceLocation
  53
+				Assert.AreEqual(line, esl.Line)
  54
+				Assert.AreEqual(column, esl.Column)
  55
+
26 56
 	def normalize(s as string):
27 57
 		return s.Trim().Replace("\r\n", "\n")
28 58
 		
45  src/Boo.OMeta.Parser/AST.boo
@@ -358,10 +358,13 @@ def newStringInterpolation(items as List):
358 358
 def newConditionalExpression(condition, trueValue, falseValue):
359 359
 	return ConditionalExpression(Condition: condition, TrueValue: trueValue, FalseValue: falseValue)
360 360
 	
361  
-def newBlockExpression(parameters as List, body):
  361
+def newBlockExpression(start as OMetaInput, end as OMetaInput, parameters as List, body):
362 362
 	node = BlockExpression(Body: body)
363 363
 	for p in parameters[0]:
364 364
 		node.Parameters.Add(p)
  365
+		
  366
+	node.EndSourceLocation = LexicalInfo("", getLine(end), getColumn(end))
  367
+		
365 368
 	return node
366 369
 	
367 370
 def newTypeofExpression(type):
@@ -439,8 +442,12 @@ def binaryOperatorFor(op):
439 442
 	
440 443
 def newAssignment(l as Expression, r as Expression):
441 444
 	return [| $l = $r |]
442  
-	
443  
-def newBlock(contents, doc):
  445
+
  446
+def newBlock(start as OMetaInput, end as OMetaInput, contents, doc):
  447
+/*
  448
+start - first symbol of the block
  449
+end - last symbol of the block
  450
+*/
444 451
 	b = Block()
445 452
 	match contents:
446 453
 		case Statement():
@@ -450,8 +457,23 @@ def newBlock(contents, doc):
450 457
 				if item:
451 458
 					b.Statements.Add(item)
452 459
 	b.Documentation  = doc
  460
+	end = findPrevCharInput(end)
  461
+	b.EndSourceLocation = LexicalInfo("", getLine(end), getColumn(end) + 1)//EndSourceLocation is the next symbol after the expression
  462
+	
453 463
 	return b
454 464
 	
  465
+def findPrevCharInput(input as OMetaInput):
  466
+	while input:		
  467
+		if isCharInput(input): return input
  468
+		input = input.Prev		
  469
+	return null
  470
+	
  471
+def isCharInput(input as OMetaInput):
  472
+	if input.IsEmpty or (not input.Head isa char): return false
  473
+	if input.Head == char('\n') or input.Head == char('\r'): return false
  474
+	return true
  475
+	
  476
+	
455 477
 def prepend(first, tail as List):
456 478
 	if first is null: return tail
457 479
 	return [first] + tail
@@ -501,4 +523,19 @@ def checkEnumerableTypeShortcut(type, stars as List):
501 523
 		(enumerable as GenericTypeReference).GenericArguments.Add(type)
502 524
 		type = enumerable
503 525
 	return enumerable
504  
-	
  526
+
  527
+def getLine(input as OMetaInput):
  528
+	if input:
  529
+		return input.GetMemo("line") or 1
  530
+	else:
  531
+		return -1
  532
+
  533
+def getColumn(input as OMetaInput):
  534
+	if input:
  535
+		return input.Position - getLineStart(input) + 1 //Columns enumeration starts from 1
  536
+	else:
  537
+		return -1
  538
+	
  539
+
  540
+def getLineStart(input as OMetaInput):
  541
+	return (input.GetMemo("lineStart") or 1) cast int
12  src/Boo.OMeta.Parser/Boo.OMeta.Parser.booproj
... ...
@@ -1,4 +1,4 @@
1  
-<?xml version="1.0" encoding="utf-8"?>
  1
+<?xml version="1.0" encoding="utf-8"?>
2 2
 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3
   <PropertyGroup>
4 4
     <ProjectGuid>{5A702DAA-43C7-45FF-9A9E-7A334FD75DD9}</ProjectGuid>
@@ -7,7 +7,7 @@
7 7
     <OutputType>Library</OutputType>
8 8
     <RootNamespace>Boo.OMeta.Parser</RootNamespace>
9 9
     <AssemblyName>Boo.OMeta.Parser</AssemblyName>
10  
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  10
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
11 11
     <TargetFrameworkProfile />
12 12
     <ProductVersion>10.0.0</ProductVersion>
13 13
     <SchemaVersion>2.0</SchemaVersion>
@@ -45,6 +45,12 @@
45 45
     <genwarnings>false</genwarnings>
46 46
   </PropertyGroup>
47 47
   <ItemGroup>
  48
+    <Reference Include="Boo.Lang">
  49
+      <HintPath>..\..\..\boo\build\Boo.Lang.dll</HintPath>
  50
+    </Reference>
  51
+    <Reference Include="Boo.Lang.Useful">
  52
+      <HintPath>..\..\..\boo\build\Boo.Lang.Useful.dll</HintPath>
  53
+    </Reference>
48 54
     <Reference Include="System.Core">
49 55
       <RequiredTargetFramework>3.5</RequiredTargetFramework>
50 56
     </Reference>
@@ -54,8 +60,6 @@
54 60
     <Reference Include="System.Xml.Linq">
55 61
       <RequiredTargetFramework>3.5</RequiredTargetFramework>
56 62
     </Reference>
57  
-    <Reference Include="Boo.Lang.Useful, Version=2.0.9.5, Culture=neutral, PublicKeyToken=32c39770e9a21a67" />
58  
-    <Reference Include="Boo.Lang, Version=2.0.9.5, Culture=neutral, PublicKeyToken=32c39770e9a21a67" />
59 63
   </ItemGroup>
60 64
   <ItemGroup>
61 65
     <Compile Include="AssemblyInfo.boo" />
31  src/Boo.OMeta.Parser/BooParser.boo
@@ -100,6 +100,9 @@ ometa BooParser < WhitespaceSensitiveTokenizer:
100 100
 
101 101
 	space = line_continuation | multi_line_comment | line_comment | super
102 102
 	
  103
+	here = "" ^ makeToken("here", null, input, input)
  104
+	prev = "" ^ makeToken("prev", null, input.Prev, input.Prev)
  105
+	
103 106
 	sqs = (SQ, --( sqs_esc | (~('\'' | '\\' | '\r' | '\n'), _)) >> s, SQ) ^ makeString(s)		
104 107
 
105 108
 	dqs = (DQ, --( dqs_esc | (~('"' | '\\' | '\r' | '\n'), _)) >> s, DQ) ^ makeString(s)		
@@ -335,15 +338,15 @@ ometa BooParser < WhitespaceSensitiveTokenizer:
335 338
 	
336 339
 	empty_block = (begin_block, (PASS, eol), end_block) ^ Block()
337 340
 	
338  
-	multi_line_block = ((begin_block_with_doc >> doc | begin_block), ++stmt >> stmts, end_block)  ^ newBlock(stmts, doc)
  341
+	multi_line_block = (here >> start, (begin_block_with_doc >> doc | begin_block), ++stmt >> stmts, end_block)  ^ newBlock(getStart(start), input, stmts, doc)
339 342
 	
340 343
 	macro_block = empty_block | multi_line_macro_block
341 344
 	
342  
-	multi_line_macro_block = ((begin_block_with_doc >> doc | begin_block), ++(stmt | type_member_stmt) >> stmts, end_block)  ^ newBlock(stmts, doc)
  345
+	multi_line_macro_block = (here >> start, (begin_block_with_doc >> doc | begin_block), ++(stmt | type_member_stmt) >> stmts, end_block)  ^ newBlock(getStart(start), input, stmts, doc)
343 346
 	
344 347
 	type_member_stmt = (type_def | method) >> tm ^ TypeMemberStatement(TypeMember: tm)
345 348
 
346  
-	single_line_block = (COLON, stmt_line >> line) ^ newBlock(line, null)
  349
+	single_line_block = (COLON >> start, stmt_line >> line) ^ newBlock(getStart(start), input, line, null)
347 350
 	
348 351
 	begin_block = COLON, INDENT
349 352
 	
@@ -416,7 +419,7 @@ ometa BooParser < WhitespaceSensitiveTokenizer:
416 419
 	
417 420
 	stmt_unless	= (UNLESS, assignment >> e, block >> condition) ^ newUnlessStatement(e, condition)
418 421
 	
419  
-	false_block = ((ELIF, assignment >> e, block >> trueBlock, false_block >> falseBlock) ^ newBlock(newIfStatement(e, trueBlock, falseBlock), null)) | \
  422
+	false_block = ((ELIF >> start, assignment >> e, block >> trueBlock, false_block >> falseBlock) ^ newBlock(getStart(start), input, newIfStatement(e, trueBlock, falseBlock), null)) | \
420 423
 		((ELSE, block >> falseBlock) ^ falseBlock) | ( "" ^ null)
421 424
 	
422 425
 	stmt_return = (
@@ -430,12 +433,12 @@ ometa BooParser < WhitespaceSensitiveTokenizer:
430 433
 	block_expression = invocation_with_block | closure_block | dsl_friendly_invocation
431 434
 	
432 435
 	invocation_with_block = (member_reference >> e and (e isa MethodInvocationExpression), \
433  
-		(closure_block | (block >> b ^ newBlockExpression([[], null], b))) >> c ^ newInvocationWithBlock(e, c) ) 
  436
+		(closure_block | (here >> start, block >> b ^ newBlockExpression(getStart(start), input, [[], null], b))) >> c ^ newInvocationWithBlock(e, c) ) 
434 437
 
435 438
 	dsl_friendly_invocation = (member_reference >> e and ((e isa MemberReferenceExpression) or (e isa ReferenceExpression)), \
436 439
 		(block) >> c) ^ newInvocation(e, [BlockExpression(Body: c)], null)
437 440
 	
438  
-	closure_block = ((DEF | DO), optional_parameters >> parameters, block >> body) ^ newBlockExpression(parameters, body)
  441
+	closure_block = ((DEF | DO) >> start, optional_parameters >> parameters, block >> body) ^ newBlockExpression(getStart(start), getMemoEnd(input), parameters, body)
439 442
 	
440 443
 	optional_parameters = method_parameters | ("" ^ [[], null])
441 444
 
@@ -598,7 +601,7 @@ ometa BooParser < WhitespaceSensitiveTokenizer:
598 601
 		
599 602
 	type_literal = (TYPEOF, LPAREN, type_reference >> type, RPAREN) ^ newTypeofExpression(type)
600 603
 		
601  
-	closure = (LBRACE, closure_parameters >> parameters, closure_stmt_list >> body, RBRACE) ^ newBlockExpression(parameters, newBlock(body, null))
  604
+	closure = (LBRACE >> start, closure_parameters >> parameters, (closure_stmt_list >> body ), RBRACE >> end ^ newBlock(getStart(start), getStart(end).Prev, body, null)) >> body ^ newBlockExpression(getStart(start), input, parameters, body)
602 605
 	
603 606
 	closure_parameters = ((optional_parameter_list >> parameters, BITWISE_OR) ^ [parameters, null]) | ("" ^ [[],null])
604 607
 	
@@ -710,3 +713,17 @@ ometa BooParser < WhitespaceSensitiveTokenizer:
710 713
 	
711 714
 	eol = (++EOL | ~_) ^ null
712 715
 
  716
+	def getStart(token as Token):
  717
+		if token:
  718
+			return token.start
  719
+		else:
  720
+			return null
  721
+		
  722
+	def getEnd(token as Token):
  723
+		if token:
  724
+			return token.end
  725
+		else:
  726
+			return null
  727
+
  728
+
  729
+
114  src/Boo.OMeta.Parser/WhitespaceSensitiveTokenizer.boo
@@ -3,9 +3,46 @@ namespace Boo.OMeta.Parser
3 3
 import System.Text
4 4
 import Boo.OMeta
5 5
 import Boo.Lang.PatternMatching
6  
-import Boo.Adt
  6
+//import Boo.Adt
  7
+
  8
+public class Token(object):
  9
+
  10
+	public final kind as string
  11
+
  12
+	public final value as string
  13
+	
  14
+	public final start as OMetaInput
  15
+	
  16
+	public final end as OMetaInput
  17
+
  18
+	public override def ToString() as string:
  19
+		return "Token($(self.kind), $(self.value))"
  20
+
  21
+	public override def Equals(o as object) as bool:
  22
+		if o is null:
  23
+			return false
  24
+		if self.GetType() is not o.GetType():
  25
+			return false
  26
+		other as Token = o
  27
+		if string.op_Inequality(self.kind, other.kind):
  28
+			return false
  29
+		if string.op_Inequality(self.value, other.value):
  30
+			return false
  31
+		return true
  32
+
  33
+	public def constructor(kind as string, value as string):
  34
+		super()
  35
+		self.kind = kind
  36
+		self.value = value
  37
+
  38
+	public def constructor(kind as string, value as string, start as OMetaInput, end as OMetaInput):
  39
+		super()
  40
+		self.kind = kind
  41
+		self.value = value
  42
+		self.start = start
  43
+		self.end = end
  44
+
7 45
 
8  
-data Token(kind as string, value as string)
9 46
 	
10 47
 ometa WhitespaceSensitiveTokenizer():
11 48
 	
@@ -31,22 +68,19 @@ ometa WhitespaceSensitiveTokenizer():
31 68
 	http://docs.python.org/ref/indentation.html
32 69
 */
33 70
 	
34  
-	scanner = (
35  
-		(
36  
-			  (((_ >> t) and (t isa Token)) ^ t) // token introduced by processDedent
  71
+	scanner = ( (((_ >> t) and (t isa Token)) ^ t) // token introduced by processDedent
37 72
 			| (((indentation >> i) and sameIndent(input, i)) ^ makeToken("eol"))
38  
-			| (((indentation >> i) and largerIndent(input, i), $(processIndent(input, i))) >> value ^ value)			
39  
-			| (((indentation >> i) and smallerIndent(input, i), $(processDedent(input, i)) >> value) ^ value)
  73
+			| ((indentation >> i) and largerIndent(input, i), $(processIndent(input, i)))
  74
+			| ((indentation >> i) and smallerIndent(input, i), $(processDedent(input, i)))
40 75
 			| ((--space, tokens >> t) ^ t)
41  
-		) >> value
42  
-	) ^ value
  76
+	)
43 77
 	
44 78
 	indentation = empty_lines, spaces
45  
-	empty_lines = ~~empty_line, ++empty_line
  79
+	empty_lines = ++empty_line
46 80
 	empty_line = spaces, newline
47 81
 	spaces = --space >> value ^ value
48 82
 	space = ' ' | '\t' | (newline and inWSA(input))
49  
-	newline = '\n' | "\r\n" | "\r"
  83
+	newline = '\n' | "\r\n" | "\r", $(newLine(input))
50 84
 	token[expected] = (scanner >> t and tokenMatches(t, expected)) ^ t
51 85
 	
52 86
 	wsa = ~~_ and inWSA(input)
@@ -77,7 +111,10 @@ ometa WhitespaceSensitiveTokenizer():
77 111
 		return wsaLevel(input, wsaLevel(input) - 1)
78 112
 
79 113
 	def success(input as OMetaInput):
80  
-		return SuccessfulMatch(input, null)
  114
+		return success(input, null)
  115
+
  116
+	def success(input as OMetaInput, value):
  117
+		return SuccessfulMatch(input, value)
81 118
 
82 119
 	def indentStack(input as OMetaInput) as List:
83 120
 		return input.GetMemo("indentStack") or [0]
@@ -91,12 +128,16 @@ ometa WhitespaceSensitiveTokenizer():
91 128
 	def largerIndent(input as OMetaInput, i):
92 129
 		if len(i) > getIndent(input):
93 130
 			return true
94  
-			
  131
+
  132
+	def smallerIndent(input as OMetaInput, i):
  133
+		return len(i) < getIndent(input)
  134
+
95 135
 	def processDedent(input as OMetaInput, i):
  136
+		original = input
96 137
 		indent = List(indentStack(input))
97 138
 		while cast(int, indent[-1]) > len(i):
98 139
 			indent.Pop()
99  
-			input = OMetaInput.Prepend(makeToken("dedent"), input)
  140
+			input = OMetaInput.Prepend(makeToken("dedent"), input, original)
100 141
 
101 142
 		input = setIndentStack(input, indent)		
102 143
 		assert sameIndent(input, i)
@@ -105,19 +146,39 @@ ometa WhitespaceSensitiveTokenizer():
105 146
 	def indentLevel(input as OMetaInput, indent as int, value as object):
106 147
 		return SuccessfulMatch(input.SetMemo("indentLevel", indent), value)
107 148
 
108  
-
109 149
 	def processIndent(input as OMetaInput, i):
110 150
 		newStack = List(indentStack(input))
111 151
 		newStack.Push(len(i))
112 152
 		return SuccessfulMatch(setIndentStack(input, newStack), makeToken("indent"))
113 153
 
114  
-	def smallerIndent(input as OMetaInput, i):
115  
-		return len(i) < getIndent(input)
116  
-
117 154
 	def getIndent(input as OMetaInput) as int:
118 155
 		return indentStack(input)[-1]
119 156
 
  157
+	def getLine(input as OMetaInput) as int:
  158
+		return input.GetMemo("line") or 1
120 159
 		
  160
+	def setLine(input as OMetaInput, value as int):
  161
+		return input.SetMemo("line", value)
  162
+
  163
+	def setLineStart(input as OMetaInput, value as int):
  164
+		return input.SetMemo("lineStart", value)
  165
+	
  166
+	def newLine(input as OMetaInput):		
  167
+		input = setLineStart(input, input.Position)
  168
+		return success(setLine(input, getLine(input) + 1))
  169
+	
  170
+def setMemoStart(input as OMetaInput, value):
  171
+	return SuccessfulMatch(input.SetMemo("start", value), null)
  172
+
  173
+def getMemoStart(input as OMetaInput):
  174
+	return input.GetMemo("start")
  175
+
  176
+def getMemoEnd(input as OMetaInput):
  177
+	return input.GetMemo("end")
  178
+	
  179
+def getBack(value):
  180
+	return value
  181
+
121 182
 def tokenMatches(token as Token, expected):
122 183
 	return expected is token.kind
123 184
 		
@@ -125,12 +186,6 @@ def tokenValue(token as Token):
125 186
 	return null if token is null
126 187
 	return token.value
127 188
 
128  
-def makeToken(kind):
129  
-	return Token(kind, kind)
130  
-		
131  
-def makeToken(kind, value):
132  
-	return Token(kind, flatString(value))
133  
-	
134 189
 def makeString(*values):
135 190
 	buffer = StringBuilder()
136 191
 	for value in values:
@@ -153,4 +208,13 @@ def flatString(buffer as StringBuilder, value):
153 208
 			buffer.Append(value)
154 209
 		otherwise:
155 210
 			for item in value:
156  
-				flatString buffer, item
  211
+				flatString buffer, item
  212
+				
  213
+def makeToken(kind):
  214
+	return Token(kind, kind)
  215
+		
  216
+def makeToken(kind, value):
  217
+	return Token(kind, flatString(value))
  218
+
  219
+def makeToken(kind, value, start, end):
  220
+	return Token(kind, flatString(value), start, end)				
18  src/Boo.OMeta.Tests/Boo.OMeta.Tests.booproj
... ...
@@ -1,4 +1,4 @@
1  
-<?xml version="1.0" encoding="utf-8"?>
  1
+<?xml version="1.0" encoding="utf-8"?>
2 2
 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3
   <PropertyGroup>
4 4
     <ProjectGuid>{39203C2D-10BB-4FD5-8B84-241908614FFA}</ProjectGuid>
@@ -7,7 +7,7 @@
7 7
     <OutputType>Library</OutputType>
8 8
     <RootNamespace>Boo.OMeta.Tests</RootNamespace>
9 9
     <AssemblyName>Boo.OMeta.Tests</AssemblyName>
10  
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  10
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
11 11
     <TargetFrameworkProfile />
12 12
     <ProductVersion>10.0.0</ProductVersion>
13 13
     <SchemaVersion>2.0</SchemaVersion>
@@ -64,9 +64,15 @@
64 64
   </ItemGroup>
65 65
   <Import Project="$(BooBinPath)\Boo.Microsoft.Build.targets" />
66 66
   <ItemGroup>
67  
-    <Reference Include="nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77" />
68  
-    <Reference Include="Boo.Lang, Version=2.0.9.5, Culture=neutral, PublicKeyToken=32c39770e9a21a67" />
69  
-    <Reference Include="Boo.Lang.Useful, Version=2.0.9.5, Culture=neutral, PublicKeyToken=32c39770e9a21a67" />
70  
-    <Reference Include="Boo.Lang.PatternMatching, Version=2.0.9.5, Culture=neutral, PublicKeyToken=32c39770e9a21a67" />
  67
+    <Reference Include="Boo.Lang">
  68
+      <HintPath>..\..\..\boo\build\Boo.Lang.dll</HintPath>
  69
+    </Reference>
  70
+    <Reference Include="Boo.Lang.PatternMatching">
  71
+      <HintPath>..\..\..\boo\build\Boo.Lang.PatternMatching.dll</HintPath>
  72
+    </Reference>
  73
+    <Reference Include="Boo.Lang.Useful">
  74
+      <HintPath>..\..\..\boo\build\Boo.Lang.Useful.dll</HintPath>
  75
+    </Reference>
  76
+    <Reference Include="nunit.framework" />
71 77
   </ItemGroup>
72 78
 </Project>
23  src/Boo.OMeta.Tests/OMetaInputTest.boo
@@ -11,12 +11,12 @@ class OMetaInputTest:
11 11
 		
12 12
 		arg = "foo"
13 13
 		input = OMetaInput.Empty()
14  
-		input1 = OMetaInput.Prepend(arg, input)
15  
-		input2 = OMetaInput.Prepend(arg, input)
  14
+		input1 = OMetaInput.Prepend(arg, input, null)
  15
+		input2 = OMetaInput.Prepend(arg, input, null)
16 16
 		
17 17
 		assert input1 == input2
18 18
 		
19  
-		input3 = OMetaInput.Prepend("bar", input)
  19
+		input3 = OMetaInput.Prepend("bar", input, null)
20 20
 		assert input1 != input3
21 21
 		
22 22
 #	[Test]
@@ -44,4 +44,19 @@ class OMetaInputTest:
44 44
 		input = OMetaInput.For(range(3))
45 45
 		while not input.IsEmpty:
46 46
 			Assert.AreSame(input.Tail, input.Tail)
47  
-			input = input.Tail
  47
+			input = input.Tail
  48
+			
  49
+	[Test]
  50
+	def OMetaInputWithMemoStoresValues():
  51
+		input = OMetaInput.For(range(3))
  52
+		
  53
+		input = input.SetMemo("a", 1)
  54
+		input = input.Tail.SetMemo("b", 2)
  55
+		
  56
+		assert input.GetMemo("a") == 1
  57
+		assert input.GetMemo("b") == 2
  58
+
  59
+		assert input.Tail.GetMemo("a") == 1
  60
+		assert input.Tail.GetMemo("b") == 2
  61
+
  62
+		
4  src/Boo.OMeta.Tests/OMetaMacroTest.boo
@@ -64,10 +64,10 @@ class OMetaMacroTest:
64 64
 	def InputVariableIsAvailableToUserCode():
65 65
 		ometa InputTest:
66 66
 			foo = _ ^ (input.Position)
67  
-			bar = $(any(input)) and (input.Position == 1)
  67
+			bar = $(any(input)) and (input.Position == 2)
68 68
 			
69 69
 		tail = OMetaInput.For("01").Tail
70  
-		assertMatch 1, InputTest().foo(tail)
  70
+		assertMatch 2, InputTest().foo(tail)
71 71
 		assertMatch char('1'), InputTest().bar(tail)
72 72
 	
73 73
 	[Test]
4  src/Boo.OMeta/Boo.OMeta.booproj
... ...
@@ -1,4 +1,4 @@
1  
-<?xml version="1.0" encoding="utf-8"?>
  1
+<?xml version="1.0" encoding="utf-8"?>
2 2
 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3
   <PropertyGroup>
4 4
     <ProjectGuid>{EED6C932-8AEE-42CB-8837-C323DC74980B}</ProjectGuid>
@@ -7,7 +7,7 @@
7 7
     <OutputType>Library</OutputType>
8 8
     <RootNamespace>Boo.OMeta</RootNamespace>
9 9
     <AssemblyName>Boo.OMeta</AssemblyName>
10  
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
  10
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
11 11
     <SourceAnalysisOverrideSettingsFile>C:\Documents and Settings\rodrigob\Application Data\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile>
12 12
     <NoStdLib>False</NoStdLib>
13 13
     <Ducky>False</Ducky>
119  src/Boo.OMeta/OMetaInput.boo
@@ -2,6 +2,7 @@ namespace Boo.OMeta
2 2
 
3 3
 import System
4 4
 import System.Collections
  5
+import System.Collections.Specialized
5 6
 
6 7
 class OMetaInput:
7 8
 
@@ -9,25 +10,25 @@ class OMetaInput:
9 10
 		return ForEnumerator(enumerable.GetEnumerator())
10 11
 		
11 12
 	static def ForEnumerator(enumerator as IEnumerator) as OMetaInput:
12  
-		return ForEnumerator(enumerator, 0)
  13
+		return ForEnumerator(enumerator, 0, null)
13 14
 		
14  
-	static def ForEnumerator(enumerator as IEnumerator, position as int) as OMetaInput:
  15
+	static def ForEnumerator(enumerator as IEnumerator, position as int, prev as OMetaInput) as OMetaInput:
15 16
 		if enumerator.MoveNext():
16  
-			return EnumeratorInput(enumerator, position)
17  
-		return EndOfEnumeratorInput(position)
  17
+			return EnumeratorInput(enumerator, position, prev)
  18
+		return EndOfEnumeratorInput(position, prev)
18 19
 		
19  
-	static def Prepend(argument, input as OMetaInput):
20  
-		return OMetaInputCons(argument, input)
  20
+	static def Prepend(argument, input as OMetaInput, prev as OMetaInput):
  21
+		return OMetaInputCons(argument, input, prev)
21 22
 		
22 23
 	static def Singleton(o):
23  
-		return Prepend(o, Empty())
  24
+		return Prepend(o, Empty(), null)
24 25
 		
25 26
 	static def Empty():
26 27
 		return OMetaInput()
27 28
 	
28 29
 	protected def constructor():
29 30
 		pass
30  
-		
  31
+
31 32
 	virtual IsEmpty as bool:
32 33
 		get: return true
33 34
 		
@@ -39,9 +40,12 @@ class OMetaInput:
39 40
 		
40 41
 	virtual Position:
41 42
 		get: return int.MaxValue
42  
-		
  43
+
  44
+	virtual Prev as OMetaInput:
  45
+		get: return null
  46
+
43 47
 	virtual def SetMemo(key as string, value) as OMetaInput:
44  
-		return OMetaInputWithMemo(key, value, self)
  48
+		return OMetaInputWithMemo(key, value, self, Prev)
45 49
 		
46 50
 	virtual def GetMemo(key as string):
47 51
 		return null
@@ -68,6 +72,9 @@ internal class DelegatingInput(OMetaInput):
68 72
 	override Position:
69 73
 		get: return _input.Position
70 74
 		
  75
+	override Prev:
  76
+		get: return _input.Prev		
  77
+		
71 78
 	override def SetMemo(key as string, value):
72 79
 		return _input.SetMemo(key, value)
73 80
 		
@@ -78,54 +85,80 @@ internal class DelegatingInput(OMetaInput):
78 85
 		return _input.ToString()
79 86
 		
80 87
 internal class OMetaInputWithMemo(DelegatingInput):
81  
-	
82  
-	final _key as string
83  
-	final _value as object
  88
+	final _dictionary as ListDictionary
84 89
 	_tail as OMetaInput
  90
+	final _prev as OMetaInput	
85 91
 	
86  
-	def constructor(key as string, value, input as OMetaInput):
  92
+	def constructor(key as string, value, input as OMetaInput, prev):
87 93
 		super(input)
88  
-		_key = key
89  
-		_value = value
  94
+		_dictionary = ListDictionary()
  95
+		_dictionary.Add(key, value)
  96
+		_prev = prev
90 97
 	
  98
+	protected def constructor(input as OMetaInput, prev, dictionary as ListDictionary):
  99
+		super(input)
  100
+		_dictionary = dictionary
  101
+		_prev = prev
  102
+	
  103
+	protected def Clone():
  104
+		dictionaryCopy = ListDictionary()
  105
+		for item as DictionaryEntry in _dictionary:	dictionaryCopy.Add(item.Key, item.Value)
  106
+		return OMetaInputWithMemo(_input, _prev, dictionaryCopy)
  107
+	
  108
+	protected def SetDictionaryEntry(key as string, value):
  109
+		_dictionary[key] = value
  110
+ 	
91 111
 	override Tail:
92  
-		get: return _tail or _tail = OMetaInputMemoTail(self, _input.Tail)
  112
+		get: return _tail or _tail = OMetaInputMemoTail(self, _input.Tail, self)
  113
+		
  114
+	override Prev:
  115
+		get: return _prev		
93 116
 			
94 117
 	override def SetMemo(key as string, value) as OMetaInput:
95  
-		if key is _key: 
96  
-			return OMetaInputWithMemo(key, value, _input)
97  
-		else:
98  
-			return OMetaInputWithMemo(key, value, self)
99  
-
  118
+		newInputWithMemo = Clone()
  119
+		newInputWithMemo.SetDictionaryEntry(key, value)
  120
+		return newInputWithMemo
  121
+		
100 122
 	override def GetMemo(key as string):
101  
-		if key is _key: return _value
102  
-		return super(key)
  123
+		if _dictionary.Contains(key): return _dictionary[key]
  124
+		return _input.GetMemo(key)
103 125
 		
104 126
 internal class OMetaInputMemoTail(DelegatingInput):
105 127
 	
106  
-	final _parent as OMetaInput
  128
+	final _parent as OMetaInputWithMemo
107 129
 	_tail as OMetaInput
  130
+	final _prev as OMetaInput
108 131
 	
109  
-	def constructor(parent as OMetaInput, input as OMetaInput):
  132
+	def constructor(parent as OMetaInputWithMemo, input as OMetaInput, prev as OMetaInput):
110 133
 		super(input)
111 134
 		_parent = parent
  135
+		_prev = prev
112 136
 		
  137
+	override Prev:
  138
+		get: return _prev
  139
+
113 140
 	override Tail:
114  
-		get: return _tail or _tail = OMetaInputMemoTail(self, _input.Tail)
  141
+		get: return _tail or _tail = OMetaInputMemoTail(_parent, _input.Tail, self)
  142
+		
115 143
 	override def SetMemo(key as string, value) as OMetaInput:
116  
-		return _parent.SetMemo(key, value).Tail
  144
+		return OMetaInputMemoTail(_parent.SetMemo(key, value), _input, _prev)
117 145
 		
118 146
 	override def GetMemo(key as string):
119 147
 		return _parent.GetMemo(key)
120 148
 		
121 149
 internal class OMetaInputCons(OMetaInput):
122  
-	[getter(Head)] _argument as object
  150
+	[getter(Head)] _head as object
123 151
 	[getter(Tail)] _tail as OMetaInput
  152
+	final _prev as OMetaInput
124 153
 	
125  
-	def constructor(argument, tail as OMetaInput):
126  
-		_argument = argument
  154
+	def constructor(head, tail as OMetaInput, prev as OMetaInput):
  155
+		_head = head
127 156
 		_tail = tail
  157
+		_prev = prev
128 158
 		
  159
+	override Prev:
  160
+		get: return _prev
  161
+
129 162
 	override IsEmpty:
130 163
 		get: return false
131 164
 
@@ -134,12 +167,14 @@ internal class EnumeratorInput(OMetaInput):
134 167
 	final _position as int
135 168
 	final _input as IEnumerator
136 169
 	final _head as object
  170
+	final _prev as OMetaInput
137 171
 	_tail as OMetaInput
138 172
 	
139  
-	internal def constructor(input as IEnumerator, position as int):
  173
+	internal def constructor(input as IEnumerator, position as int, prev as OMetaInput):
140 174
 		_input = input
141 175
 		_head = input.Current
142 176
 		_position = position
  177
+		_prev = prev
143 178
 		
144 179
 	override Position:
145 180
 		get: return _position
@@ -151,15 +186,25 @@ internal class EnumeratorInput(OMetaInput):
151 186
 		get: return _head
152 187
 	
153 188
 	override Tail:
154  
-		get: return _tail or _tail = ForEnumerator(_input, _position + 1)
  189
+		get: return _tail or _tail = ForEnumerator(_input, _position + 1, self)
  190
+	
  191
+	override Prev:
  192
+		get: return _prev
155 193
 		
156 194
 	override def ToString():
157 195
 		return "OMetaInput(Head: ${Head}, Position: ${Position})"
158 196
 		
159  
-internal class EndOfEnumeratorInput(OMetaInput):
160  
-	
161  
-	def constructor(position as int):
162  
-		_position = position
  197
+
163 198
 		
  199
+internal class EndOfEnumeratorInput(OMetaInput):	
  200
+	final _prev as OMetaInput
  201
+
  202
+	def constructor(position as int, prev as OMetaInput):
  203
+		_position = position
  204
+		_prev = prev
  205
+
  206
+	override Prev:
  207
+		get: return _prev
  208
+
164 209
 	[getter(Position)]
165 210
 	_position as int
6  src/Boo.OMeta/OMetaMacroProcessor.boo
@@ -36,6 +36,7 @@ class OMetaMacroProcessor:
36 36
 				case ExpressionStatement(Expression: [| $(ReferenceExpression(Name: name)) = $pattern |]):
37 37
 					m0 = [|
38 38
 						private def $("${name}_rule")(context as OMetaEvaluationContext, input_ as OMetaInput) as OMetaMatch:
  39
+							lastMatch as OMetaMatch = SuccessfulMatch(input_, null)
39 40
 							$(OMetaMacroRuleProcessor(name, options, ruleNames).expand(pattern))
40 41
 					|]
41 42
 					type.Members.Add(m0)
@@ -53,17 +54,18 @@ class OMetaMacroProcessor:
53 54
 				case ExpressionStatement(Expression: [| $(ReferenceExpression(Name: name))[$arg] = $pattern |]):
54 55
 					m0 = [|
55 56
 						private def $("${name}_rule")(context as OMetaEvaluationContext, input_ as OMetaInput) as OMetaMatch:
  57
+							lastMatch as OMetaMatch = SuccessfulMatch(input_, null)
56 58
 							$(OMetaMacroRuleProcessor(name, options, ruleNames).expand(pattern, arg))
57 59
 					|]
58 60
 					type.Members.Add(m0)
59 61
 					m1 = [|
60 62
 						def $name(input as OMetaInput, $arg):
61  
-							return Apply($name, OMetaInput.Prepend($arg, input))
  63
+							return Apply($name, OMetaInput.Prepend($arg, input, null))
62 64
 					|]
63 65
 					type.Members.Add(m1)
64 66
 					m2 = [|
65 67
 						def $name(input as System.Collections.IEnumerable, $arg):
66  
-							return Apply($name, OMetaInput.Prepend($arg, OMetaInput.For(input)))
  68
+							return Apply($name, OMetaInput.Prepend($arg, OMetaInput.For(input), null))
67 69
 					|]
68 70
 					type.Members.Add(m2)
69 71
 					
15  src/Boo.OMeta/OMetaMacroRuleProcessor.boo
@@ -171,22 +171,23 @@ class OMetaMacroRuleProcessor:
171 171
 		return e
172 172
 		
173 173
 	def expand(block as Block, e as Expression, input as Expression, lastMatch as ReferenceExpression):
  174
+		lm as Expression = [| $lastMatch.Input |]
  175
+		
174 176
 		match e:
175  
-			case SpliceExpression(Expression: rule):
176  
-				block.Add([| $lastMatch = $(processVariables(rule, input)) |])
177  
-				
  177
+			case SpliceExpression(Expression: rule):				
  178
+				block.Add([| $lastMatch = $(processVariables(rule, lm)) |])				
178 179
 			case [| $rule[$arg] |]:
179 180
 				newInput = uniqueName()
180 181
 				effectiveArg = effectiveArgForRule(arg)
181  
-				block.Add([| $newInput = OMetaInput.Prepend($effectiveArg, $input) |])
  182
+				block.Add([| $newInput = OMetaInput.Prepend($effectiveArg, $input, null) |])
182 183
 				expand block, rule, newInput, lastMatch
183 184
 				
184 185
 			case [| $pattern and $predicate |]:
185 186
 				oldInput = uniqueName()
186 187
 				block.Add([| $oldInput = $input |])
187  
-				expand block, pattern, input, lastMatch
  188
+				expand block, pattern, input, lastMatch				
188 189
 				checkPredicate = [|
189  
-					if $lastMatch isa SuccessfulMatch and not $(processVariables(predicate, input)):
  190
+					if $lastMatch isa SuccessfulMatch and not $(processVariables(predicate, lm)):
190 191
 						$lastMatch = FailedMatch($oldInput, PredicateFailure($(predicate.ToCodeString())))
191 192
 				|]
192 193
 				block.Add(checkPredicate)
@@ -198,7 +199,7 @@ class OMetaMacroRuleProcessor:
198 199
 						block:
199 200
 							smatch = $lastMatch as SuccessfulMatch
200 201
 							if smatch is not null:
201  
-								$lastMatch = SuccessfulMatch(smatch.Input, $(processVariables(value, input)))
  202
+								$lastMatch = SuccessfulMatch(smatch.Input, $(processVariables(value, lm)))
202 203
 					|].Body
203 204
 					block.Add(code)
204 205
 				
2  src/Boo.OMeta/TokensMacro.boo
@@ -29,7 +29,7 @@ it generates:
29 29
 	for stmt in tokens.Body.Statements:
30 30
 		match stmt:
31 31
 			case ExpressionStatement(Expression: [| $name = $pattern |]):
32  
-				e = [| $name = $pattern >> value ^ makeToken($(name.ToString()), value) |]
  32
+				e = [| $name = (("" ^ makeToken("here", null, input, null)) >> start, $pattern >> value) ^ makeToken($(name.ToString()), value, (start as Token).start, null) |]
33 33
 				e.LexicalInfo = stmt.LexicalInfo
34 34
 				block.Add(e)
35 35
 				
3  src/OMetaParserConsole/OMetaParserConsole.booproj
@@ -66,8 +66,5 @@
66 66
       <Name>Boo.OMeta</Name>
67 67
     </ProjectReference>
68 68
   </ItemGroup>
69  
-  <ItemGroup>
70  
-    <None Include="app.config" />
71  
-  </ItemGroup>
72 69
   <Import Project="$(BooBinPath)\Boo.Microsoft.Build.targets" />
73 70
 </Project>
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.