1// This file is part of SmallBASIC
2//
3// inlined hotspots
4//
5// This program is distributed under the terms of the GPL v2.0 or later
6// Download the GNU Public License (GPL) from www.gnu.org
7//
8// Copyright(C) 2014 Chris Warren-Smith
9
10#include "include/var_map.h"
11#include "common/var_eval.h"
12
13void err_evsyntax(void);
14void err_varisarray(void);
15void err_varisnotarray(void);
16void err_notavar(void);
17
18/**
19 * @ingroup var
20 *
21 * returns the next integer and moves the IP 4 bytes forward.
22 *
23 * R(long int) <- Code[IP]; IP+=j
24 */
25static inline uint32_t code_getnext32(void) {
26 uint32_t v;
27 memcpy(&v, prog_source + prog_ip, 4);
28 prog_ip += 4;
29 return v;
30}
31
32/**
33 * @ingroup var
34 *
35 * returns the next 64bit and moves the instruction pointer to the next instruction
36 *
37 * R(double) <- Code[IP]; IP+=j
38 */
39static inline var_num_t code_getreal() {
40 var_num_t v;
41 memcpy(&v, prog_source + prog_ip, sizeof(var_num_t));
42 prog_ip += sizeof(var_num_t);
43 return v;
44}
45
46/**
47 * @ingroup var
48 *
49 * returns the next var_int_t and moves the instruction pointer to the next instruction
50 */
51static inline var_int_t code_getint() {
52 var_int_t v;
53 memcpy(&v, prog_source + prog_ip, sizeof(var_int_t));
54 prog_ip += sizeof(var_int_t);
55 return v;
56}
57
58/**
59 * @ingroup var
60 *
61 * returns the floating-point value of a var.
62 * if v is string it will converted to double.
63 *
64 * @param v the variable
65 * @return the numeric value of a variable
66 */
67static inline var_num_t v_getval(var_t *v) {
68 switch (v ? v->type : -1) {
69 case V_INT:
70 return v->v.i;
71 case V_NUM:
72 return v->v.n;
73 case V_STR:
74 return numexpr_sb_strtof(v->v.p.ptr);
75 case V_PTR:
76 return v->v.ap.p;
77 case V_MAP:
78 return map_to_int(v);
79 default:
80 if (v == NULL) {
81 err_evsyntax();
82 } else {
83 err_varisarray();
84 }
85 }
86 return 0;
87}
88
89/**
90 * @ingroup var
91 *
92 * returns the integer value of a var.
93 * if v is string it will converted to integer.
94 *
95 * @param v the variable
96 * @return the integer value of a variable
97 */
98static inline var_int_t v_igetval(var_t *v) {
99 switch (v ? v->type : -1) {
100 case V_INT:
101 return v->v.i;
102 case V_NUM:
103 return v->v.n;
104 case V_STR:
105 return numexpr_strtol(v->v.p.ptr);
106 case V_PTR:
107 return v->v.ap.p;
108 case V_MAP:
109 return map_to_int(v);
110 default:
111 if (v == NULL) {
112 err_evsyntax();
113 } else {
114 err_varisarray();
115 }
116 }
117 return 0;
118}
119
120/**
121 * @ingroup exec
122 *
123 * variant of code_getvarptr() derefence until left parenthesis found
124 *
125 * R(var_t*) <- Code[IP]; IP += 2;
126 *
127 * @return the var_t*
128 */
129static inline var_t *code_getvarptr_parens(int until_parens) {
130 var_t *var_p = NULL;
131
132 if (code_peek() == kwTYPE_VAR) {
133 code_skipnext();
134 var_p = tvar[code_getaddr()];
135 if (code_peek() == kwTYPE_UDS_EL) {
136 var_p = code_resolve_map(var_p, until_parens);
137 } else {
138 switch (var_p->type) {
139 case V_MAP:
140 var_p = code_resolve_map(var_p, until_parens);
141 break;
142 case V_ARRAY:
143 var_p = code_resolve_varptr(var_p, until_parens);
144 break;
145 default:
146 if (!until_parens && code_peek() == kwTYPE_LEVEL_BEGIN) {
147 err_varisnotarray();
148 }
149 }
150 }
151 }
152
153 if (var_p == NULL && !prog_error) {
154 err_notavar();
155 return tvar[0];
156 }
157
158 return var_p;
159}
160
161/**
162 * @ingroup var
163 *
164 * initialize a variable
165 *
166 * @param v the variable
167 */
168static inline void v_init(var_t *v) {
169 v->type = V_INT;
170 v->const_flag = 0;
171 v->v.i = 0;
172}
173
174/**
175 * @ingroup var
176 *
177 * frees the var or releases it back into the pool
178 */
179static inline void v_detach(var_t *v) {
180 if (v->pooled) {
181 v_pool_free(v);
182 } else {
183 free(v);
184 }
185}
186
187/**
188 * @ingroup var
189 *
190 * free variable's data.
191 *
192 * @warning it frees only the data, not the variable
193 *
194 * @param v the variable
195 */
196static inline void v_free(var_t *v) {
197 switch (v->type) {
198 case V_STR:
199 if (v->v.p.owner) {
200 free(v->v.p.ptr);
201 }
202 break;
203 case V_ARRAY:
204 v_array_free(v);
205 break;
206 case V_MAP:
207 map_free(v);
208 break;
209 }
210 v_init(v);
211}
212