s_expression.cpp revision 497baf4e4a6a0a2f247c7bfb9bf69a2b93c2c19f
1/* -*- c++ -*- */
2/*
3 * Copyright © 2010 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25#include <assert.h>
26#include "s_expression.h"
27
28s_symbol::s_symbol(const char *tmp, size_t n)
29{
30   this->str = ralloc_strndup (this, tmp, n);
31   assert(this->str != NULL);
32}
33
34s_list::s_list()
35{
36}
37
38static void
39skip_whitespace(const char *& src)
40{
41   src += strspn(src, " \v\t\r\n");
42   /* Also skip Scheme-style comments: semi-colon 'til end of line */
43   if (src[0] == ';') {
44      src += strcspn(src, "\n");
45      skip_whitespace(src);
46   }
47}
48
49static s_expression *
50read_atom(void *ctx, const char *& src)
51{
52   s_expression *expr = NULL;
53
54   skip_whitespace(src);
55
56   size_t n = strcspn(src, "( \v\t\r\n);");
57   if (n == 0)
58      return NULL; // no atom
59
60   // Check if the atom is a number.
61   char *float_end = NULL;
62   double f = glsl_strtod(src, &float_end);
63   if (float_end != src) {
64      char *int_end = NULL;
65      int i = strtol(src, &int_end, 10);
66      // If strtod matched more characters, it must have a decimal part
67      if (float_end > int_end)
68	 expr = new(ctx) s_float(f);
69      else
70	 expr = new(ctx) s_int(i);
71   } else {
72      // Not a number; return a symbol.
73      expr = new(ctx) s_symbol(src, n);
74   }
75
76   src += n;
77
78   return expr;
79}
80
81s_expression *
82s_expression::read_expression(void *ctx, const char *&src)
83{
84   assert(src != NULL);
85
86   s_expression *atom = read_atom(ctx, src);
87   if (atom != NULL)
88      return atom;
89
90   skip_whitespace(src);
91   if (src[0] == '(') {
92      ++src;
93
94      s_list *list = new(ctx) s_list;
95      s_expression *expr;
96
97      while ((expr = read_expression(ctx, src)) != NULL) {
98	 list->subexpressions.push_tail(expr);
99      }
100      skip_whitespace(src);
101      if (src[0] != ')') {
102	 printf("Unclosed expression (check your parenthesis).\n");
103	 return NULL;
104      }
105      ++src;
106      return list;
107   }
108   return NULL;
109}
110
111void s_int::print()
112{
113   printf("%d", this->val);
114}
115
116void s_float::print()
117{
118   printf("%f", this->val);
119}
120
121void s_symbol::print()
122{
123   printf("%s", this->str);
124}
125
126void s_list::print()
127{
128   printf("(");
129   foreach_iter(exec_list_iterator, it, this->subexpressions) {
130      s_expression *expr = (s_expression*) it.get();
131      expr->print();
132      if (!expr->next->is_tail_sentinel())
133	 printf(" ");
134   }
135   printf(")");
136}
137
138// --------------------------------------------------
139
140bool
141s_pattern::match(s_expression *expr)
142{
143   switch (type)
144   {
145   case EXPR:   *p_expr = expr; break;
146   case LIST:   if (expr->is_list())   *p_list   = (s_list *)   expr; break;
147   case SYMBOL: if (expr->is_symbol()) *p_symbol = (s_symbol *) expr; break;
148   case NUMBER: if (expr->is_number()) *p_number = (s_number *) expr; break;
149   case INT:    if (expr->is_int())    *p_int    = (s_int *)    expr; break;
150   case STRING:
151      s_symbol *sym = SX_AS_SYMBOL(expr);
152      if (sym != NULL && strcmp(sym->value(), literal) == 0)
153	 return true;
154      return false;
155   };
156
157   return *p_expr == expr;
158}
159
160bool
161s_match(s_expression *top, unsigned n, s_pattern *pattern, bool partial)
162{
163   s_list *list = SX_AS_LIST(top);
164   if (list == NULL)
165      return false;
166
167   unsigned i = 0;
168   foreach_iter(exec_list_iterator, it, list->subexpressions) {
169      if (i >= n)
170	 return partial; /* More actual items than the pattern expected */
171
172      s_expression *expr = (s_expression *) it.get();
173      if (expr == NULL || !pattern[i].match(expr))
174	 return false;
175
176      i++;
177   }
178
179   if (i < n)
180      return false; /* Less actual items than the pattern expected */
181
182   return true;
183}
184