1 //
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 5 Jun 06 Brian Frank Creation
7 //
8
9 **
10 ** ScanForUsingsAndTypes is the first phase in a two pass parser. Here
11 ** we scan thru the tokens to parse using declarations and type definitions
12 ** so that we can fully define the namespace of types. The result of this
13 ** step is to populate each CompilationUnit's using and types, and the
14 ** PodDef.typeDefs map.
15 **
16 class ScanForUsingsAndTypes : CompilerStep
17 {
18
19 //////////////////////////////////////////////////////////////////////////
20 // Construction
21 //////////////////////////////////////////////////////////////////////////
22
23 **
24 ** Constructor takes the associated Compiler
25 **
26 new make(Compiler compiler)
27 : super(compiler)
28 {
29 }
30
31 //////////////////////////////////////////////////////////////////////////
32 // Methods
33 //////////////////////////////////////////////////////////////////////////
34
35 **
36 ** Run the step
37 **
38 override Void run()
39 {
40 log.debug("ScanForUsingsAndTypes")
41
42 allTypes := Str:TypeDef[:]
43
44 units.each |CompilationUnit unit|
45 {
46 UsingAndTypeScanner.make(compiler, unit, allTypes).parse
47 }
48 bombIfErr
49
50 compiler.pod.typeDefs = allTypes
51 }
52
53 }
54
55 **************************************************************************
56 ** UsingAndTypeScanner
57 **************************************************************************
58
59 class UsingAndTypeScanner : CompilerSupport
60 {
61 new make(Compiler compiler, CompilationUnit unit, Str:TypeDef allTypes)
62 : super(compiler)
63 {
64 this.unit = unit
65 this.tokens = unit.tokens
66 this.pos = 0
67 this.allTypes = allTypes
68 if (compiler != null) this.isSys = compiler.isSys
69 }
70
71 Void parse()
72 {
73 // sys is imported implicitly (unless this is sys itself)
74 if (!isSys)
75 unit.usings.add(Using.make(unit.location, "sys"))
76
77 // scan tokens quickly looking for keywords
78 inClassHeader := false
79 while (true)
80 {
81 tok := consume
82 if (tok.kind === Token.eof) break
83 switch (tok.kind)
84 {
85 case Token.usingKeyword:
86 parseUsing(tok)
87 case Token.lbrace:
88 inClassHeader = false
89 case Token.classKeyword:
90 case Token.mixinKeyword:
91 case Token.enumKeyword:
92 if (!inClassHeader)
93 {
94 inClassHeader = true;
95 parseType(tok);
96 }
97 }
98 }
99 }
100
101 private Void parseUsing(TokenVal tok)
102 {
103 imp := Using.make(tok, consumeId)
104 if (curt === Token.doubleColon)
105 {
106 consume
107 imp.typeName = consumeId
108 if (curt === Token.asKeyword)
109 {
110 consume
111 imp.asName = consumeId
112 }
113 }
114 unit.usings.add(imp)
115 }
116
117 private Void parseType(TokenVal tok)
118 {
119 name := consumeId
120 typeDef := TypeDef.make(ns, tok, unit, name)
121 unit.types.add(typeDef)
122
123 // set enum/mixin flag to use by Parser
124 if (tok.kind === Token.mixinKeyword)
125 typeDef.flags |= FConst.Mixin
126 else if (tok.kind === Token.enumKeyword)
127 typeDef.flags |= FConst.Enum
128
129 // check for duplicate type names
130 if (allTypes.containsKey(name))
131 err("Duplicate type name '$name'", typeDef.location)
132 else
133 allTypes[name] = typeDef
134 }
135
136 private Str consumeId()
137 {
138 id := consume
139 if (id.kind != Token.identifier)
140 {
141 err("Expected identifier", id)
142 return ""
143 }
144 return (Str)id.val
145 }
146
147 private TokenVal consume()
148 {
149 return tokens[pos++]
150 }
151
152 private Token curt()
153 {
154 return tokens[pos].kind
155 }
156
157 private CompilationUnit unit
158 private TokenVal[] tokens
159 private Int pos
160 private Bool isSys := false
161 private Str:TypeDef allTypes
162
163 }