1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity average)
4 module dil.semantic.Analysis;
5 
6 import dil.ast.Node,
7        dil.ast.Expressions;
8 import dil.semantic.Scope,
9        dil.semantic.Types,
10        dil.semantic.TypesEnum;
11 import dil.lexer.IdTable;
12 import dil.Compilation;
13 import common;
14 
15 /// Common semantics for pragma declarations and statements.
16 void pragmaSemantic(Scope scop, Token* pragmaLoc,
17                     Identifier* ident,
18                     Expression[] args)
19 {
20   if (ident is Ident.msg)
21     pragma_msg(scop, pragmaLoc, args);
22   else if (ident is Ident.lib)
23     pragma_lib(scop, pragmaLoc, args);
24   // else
25   //   scop.error(begin, "unrecognized pragma");
26 }
27 
28 /// Evaluates a msg pragma.
29 void pragma_msg(Scope scop, Token* pragmaLoc, Expression[] args)
30 {
31   if (args.length == 0)
32     return /*scop.error(pragmaLoc, "expected expression arguments to pragma")*/;
33 
34   foreach (arg; args)
35   {
36     auto e = arg/+.evaluate()+/;
37     if (e is null)
38     {
39       // scop.error(e.begin, "expression is not evaluatable at compile time");
40     }
41     else if (auto stringExpr = e.Is!(StringExpr))
42       // Print string to standard output.
43       Stdout(stringExpr.getString());
44     else
45     {
46       // scop.error(e.begin, "expression must evaluate to a string");
47     }
48   }
49   // Print a newline at the end.
50   Stdout('\n');
51 }
52 
53 /// Evaluates a lib pragma.
54 void pragma_lib(Scope scop, Token* pragmaLoc, Expression[] args)
55 {
56   if (args.length != 1)
57     return /*scop.error(pragmaLoc, "expected one expression argument to pragma")*/;
58 
59   auto e = args[0]/+.evaluate()+/;
60   if (e is null)
61   {
62     // scop.error(e.begin, "expression is not evaluatable at compile time");
63   }
64   else if (auto stringExpr = e.Is!(StringExpr))
65   {
66     // TODO: collect library paths in Module?
67     // scop.modul.addLibrary(stringExpr.getString());
68   }
69   else
70   {
71     // scop.error(e.begin, "expression must evaluate to a string");
72   }
73 }
74 
75 /// Returns true if the first branch (of a debug declaration/statement) or
76 /// false if the else-branch should be compiled in.
77 bool debugBranchChoice(Token* cond, CompilationContext context)
78 {
79   if (cond)
80   {
81     if (cond.kind == TOK.Identifier)
82     {
83       if (context.findDebugId(cond.ident.str))
84         return true;
85     }
86     else if (cond.uint_ <= context.debugLevel)
87       return true;
88   }
89   else if (1 <= context.debugLevel)
90     return true;
91   return false;
92 }
93 
94 /// Returns true if the first branch (of a version declaration/statement) or
95 /// false if the else-branch should be compiled in.
96 bool versionBranchChoice(Token* cond, CompilationContext context)
97 {
98   assert(cond);
99   if (cond.kind == TOK.Identifier || cond.kind == TOK.Unittest)
100   {
101     if (context.findVersionId(cond.ident.str))
102       return true;
103   }
104   else if (cond.uint_ >= context.versionLevel)
105     return true;
106   return false;
107 }
108 
109 /// Performs an integer promotion on the type of e, according to spec.
110 void integerPromotion(Expression e)
111 {
112   assert(e.type !is null);
113   switch (e.type.baseType().tid)
114   {
115   case TYP.Bool, TYP.Int8, TYP.UInt8, TYP.Int16,
116        TYP.UInt16, TYP.Char, TYP.WChar:
117     e.type = Types.Int32;
118     break;
119   case TYP.DChar:
120     e.type = Types.UInt32;
121     break;
122   default:
123   }
124 }