Advertisement
rotrevrep

Expression parser

Sep 11th, 2019
2,445
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Vala 5.37 KB | None | 0 0
  1. namespace Vcl {
  2.     public class Reader : GLib.Object {
  3.         public Reader (string text) {
  4.             GLib.Object (text : text);
  5.         }
  6.        
  7.         internal int position;
  8.        
  9.         construct {
  10.             position = text.length;
  11.         }
  12.        
  13.         public unichar peek() {
  14.             int pos = position;
  15.             unichar u = 0;
  16.             if (!text.get_prev_char (ref pos, out u))
  17.                 return 0;
  18.             return u;
  19.         }
  20.        
  21.         public unichar read() {
  22.             unichar u = 0;
  23.             if (!text.get_prev_char (ref position, out u))
  24.                 return 0;
  25.             return u;
  26.         }
  27.        
  28.         public bool eof { get { return peek() == 0; } }
  29.        
  30.         public string text { get; construct; }
  31.     }
  32.    
  33.     public errordomain ExpressionError {
  34.         UNKNOWN
  35.     }
  36.    
  37.     public abstract class Expression : GLib.Object {
  38.         public Expression previous { get; set; }
  39.        
  40.         public Expression next { get; set; }
  41.        
  42.         public string name { get; set; }
  43.        
  44.         static Character parse_character (Reader str) {
  45.             str.read();
  46.             unichar c = str.read();
  47.             if (c == '\'' && str.peek() != '\\')
  48.                 throw new ExpressionError.UNKNOWN ("null char");
  49.             if (c == '\'')
  50.                 str.read();
  51.             if (str.read() != '\'')
  52.                 throw new ExpressionError.UNKNOWN ("invalid char");
  53.             return new Character (c.to_string());
  54.         }
  55.        
  56.         static String parse_string (Reader str) {
  57.             str.read();
  58.             int pos = str.position;
  59.             bool multi = false;
  60.             if (str.read() == '"' && str.read() == '"')
  61.                 multi = true;
  62.             else
  63.                 str.position = pos;
  64.             var builder = new StringBuilder("");
  65.             bool end = false;
  66.             while (!str.eof) {
  67.                 if (str.peek() != '"')
  68.                     builder.prepend_unichar (str.read());
  69.                 if (str.peek() == '"' && !multi) {
  70.                     str.read();
  71.                     if (str.peek() == '\\') {
  72.                         str.read();
  73.                         builder.prepend_unichar ('"');
  74.                         continue;
  75.                     }
  76.                     end = true;
  77.                     break;
  78.                 }
  79.                 pos = str.position;
  80.                 if (str.read() == '"' && str.read() == '"' && str.read() == '"' && multi) {
  81.                     end = true;
  82.                     break;
  83.                 }
  84.                 else
  85.                     str.position = pos;
  86.             }
  87.             if (!end)
  88.                 throw new ExpressionError.UNKNOWN ("can't find end of string");
  89.             return new String (builder.str);
  90.         }
  91.        
  92.         static Variable parse_variable (Reader str) {
  93.             var builder = new StringBuilder();
  94.             while (str.peek().isalnum() || str.peek() == '_')
  95.                 builder.prepend_unichar (str.read());
  96.             return new Variable (builder.str);
  97.         }
  98.        
  99.         static Method parse_method (Reader str) throws ExpressionError {
  100.             str.read();
  101.             var meth = new Method("");
  102.             meth.parameters.add (parse_expression (str));
  103.             while (str.peek() == ',')
  104.                 meth.parameters.insert (0, parse_expression (str));
  105.             if (str.read() != '(')
  106.                 throw new ExpressionError.UNKNOWN ("can't find start of method parameters");
  107.             while (str.peek().isspace())
  108.                 str.read();
  109.             var builder = new StringBuilder();
  110.             while (str.peek().isalnum() || str.peek() == '_')
  111.                 builder.prepend_unichar (str.read());
  112.             meth.name = builder.str;
  113.             return meth;
  114.         }
  115.        
  116.         static Array parse_array (Reader str) throws ExpressionError {
  117.             str.read();
  118.             var index = parse_expression (str);
  119.             if (str.read() != '[')
  120.                 throw new ExpressionError.UNKNOWN ("can't find start of array index");
  121.             while (str.peek().isspace())
  122.                 str.read();
  123.             var builder = new StringBuilder();
  124.             while (str.peek().isalnum() || str.peek() == '_')
  125.                 builder.prepend_unichar (str.read());
  126.             var arr = new Array (builder.str);
  127.             arr.index = index;
  128.             return arr;
  129.         }
  130.        
  131.         static Expression parse_expression (Reader str) throws ExpressionError {
  132.             while (str.peek().isspace())
  133.                 str.read();
  134.             Expression expr = null;
  135.             if (str.peek().isalnum() || str.peek() == '_')
  136.                 expr = parse_variable (str);
  137.             else if (str.peek() == ')')
  138.                 expr = parse_method (str);
  139.             else if (str.peek() == ']')
  140.                 expr = parse_array (str);
  141.             else if (str.peek() == '"')
  142.                 expr = parse_string (str);
  143.             else if (str.peek() == '\'')
  144.                 expr = parse_character (str);
  145.             while (str.peek().isspace())
  146.                 str.read();
  147.             if (str.peek() == '.') {
  148.                 str.read();
  149.                 var e = parse_expression (str);
  150.                 e.next = expr;
  151.                 expr.previous = e;
  152.             }
  153.             return expr;
  154.         }
  155.        
  156.         public static Expression parse (string data) throws ExpressionError {
  157.             var str = new Reader (data);
  158.             return parse_expression (str);
  159.         }
  160.     }
  161.    
  162.     public class Array : Expression {
  163.         public Array (string name = "") { GLib.Object (name : name); }
  164.        
  165.         public Expression index { get; set; }
  166.     }
  167.    
  168.     public class Method : Expression {
  169.         Gee.ArrayList<Expression> expr_list;
  170.        
  171.         public Method (string name = "") { GLib.Object (name : name); }
  172.        
  173.         construct {
  174.             expr_list = new Gee.ArrayList<Expression>();
  175.         }
  176.        
  177.         public Gee.List<Expression> parameters {
  178.             get {
  179.                 return expr_list;
  180.             }
  181.         }
  182.     }
  183.    
  184.     public class Variable : Expression {
  185.         public Variable (string name = "") { GLib.Object (name : name); }
  186.     }
  187.    
  188.     public class String : Expression {
  189.         public String (string name = "") { GLib.Object (name : name); }
  190.     }
  191.    
  192.     public class Character : Expression {
  193.         public Character (string name = "") { GLib.Object (name : name); }
  194.     }
  195. }
  196.  
  197. public static void main (string[] args) {
  198.     string data;
  199.     FileUtils.get_contents ("data", out data);
  200.     var expr = Vcl.Expression.parse (data);
  201.     while (expr is Vcl.Expression) {
  202.         print ("%s\n", expr.get_type().name());
  203.         if (expr is Vcl.Method) {
  204.             foreach (var e in (expr as Vcl.Method).parameters)
  205.                 print ("\t%s\n", e.get_type().name());
  206.         }
  207.         expr = expr.previous;
  208.     }
  209. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement