Skip to content

Commit 6da830a

Browse files
committed
Added BoolOp, None Variable
* py_types -added BoolOpInstr * py_instrcreator - added boolOpInstr * py_interpreter - added handler for boolop, none, variable,
1 parent 7b31123 commit 6da830a

File tree

3 files changed

+86
-3
lines changed

3 files changed

+86
-3
lines changed

src/cse-machine/py_instrCreator.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Environment } from "./environment";
2-
import { AppInstr, AssmtInstr, BinOpInstr, BranchInstr, EnvInstr, Instr, InstrType, PyNode, UnOpInstr } from "./py_types";
2+
import { AppInstr, AssmtInstr, BinOpInstr, BranchInstr, EnvInstr, Instr, InstrType, PyNode, UnOpInstr, BoolOpInstr } from "./py_types";
33
import { TokenType } from "../tokens";
44

55
export const popInstr = (srcNode: PyNode): Instr => ({
@@ -64,3 +64,9 @@ export const unOpInstr = (symbol: TokenType, srcNode: PyNode): UnOpInstr => ({
6464
symbol,
6565
srcNode
6666
})
67+
68+
export const boolOpInstr = (symbol: TokenType, srcNode: PyNode): BoolOpInstr => ({
69+
instrType: InstrType.BOOL_OP,
70+
symbol,
71+
srcNode
72+
});

src/cse-machine/py_interpreter.ts

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { StmtNS, ExprNS } from '../ast-types';
22
import { PyContext } from './py_context';
33
import { PyControl, PyControlItem } from './py_control';
4-
import { PyNode, Instr, InstrType, UnOpInstr, BinOpInstr } from './py_types';
4+
import { PyNode, Instr, InstrType, UnOpInstr, BinOpInstr, BoolOpInstr } from './py_types';
55
import { Stash, Value, ErrorValue } from './stash';
66
import { IOptions } from '..';
77
import * as instr from './py_instrCreator';
@@ -137,6 +137,32 @@ const pyCmdEvaluators: { [type: string]: CmdEvaluator } = {
137137
control.push(binary.left);
138138
},
139139

140+
'BoolOp': (command, context, control, stash, isPrelude) => {
141+
const boolOp = command as ExprNS.BoolOp;
142+
control.push(instr.boolOpInstr(boolOp.operator.type, boolOp));
143+
control.push(boolOp.right);
144+
control.push(boolOp.left);
145+
},
146+
147+
'None': (command, context, control, stash, isPrelude) => {
148+
stash.push({ type: 'undefined' });
149+
},
150+
151+
'Variable': (command, context, control, stash, isPrelude) => {
152+
const variable = command as ExprNS.Variable;
153+
const name = variable.name.lexeme;
154+
// For now, we only handle built in constants.
155+
// In a future commit, we will look up variables in the environment.
156+
if (name === 'True') {
157+
stash.push({ type: 'bool', value: true });
158+
} else if (name === 'False') {
159+
stash.push({ type: 'bool', value: false });
160+
} else {
161+
// Throw an error for undefined variables for now
162+
throw new Error(`NameError: name '${name}' is not defined`);
163+
}
164+
},
165+
140166
/**
141167
* Instruction Handlers
142168
*/
@@ -170,4 +196,50 @@ const pyCmdEvaluators: { [type: string]: CmdEvaluator } = {
170196
stash.push(result);
171197
}
172198
},
199+
200+
[InstrType.BOOL_OP]: function (command: PyControlItem, context: PyContext, control: PyControl, stash: Stash, isPrelude:
201+
boolean) {
202+
const instr = command as BoolOpInstr;
203+
const rightValue = stash.pop();
204+
const leftValue = stash.pop();
205+
206+
if (!leftValue || !rightValue) {
207+
throw new Error("RuntimeError: Boolean operation requires two operands.");
208+
}
209+
210+
// Implement Python's short-circuiting logic
211+
if (instr.symbol === TokenType.OR) {
212+
// If left is truthy, return left. Otherwise, return right.
213+
let isLeftTruthy = false;
214+
if (leftValue.type === 'bool') isLeftTruthy = leftValue.value;
215+
else if (leftValue.type === 'bigint') isLeftTruthy = leftValue.value !== 0n;
216+
else if (leftValue.type === 'number') isLeftTruthy = leftValue.value !== 0;
217+
else if (leftValue.type === 'string') isLeftTruthy = leftValue.value !== '';
218+
else if (leftValue.type === 'undefined') isLeftTruthy = false;
219+
else isLeftTruthy = true; // Other types are generally truthy
220+
221+
if (isLeftTruthy) {
222+
stash.push(leftValue);
223+
} else {
224+
stash.push(rightValue);
225+
}
226+
} else if (instr.symbol === TokenType.AND) {
227+
// If left is falsy, return left. Otherwise, return right.
228+
let isLeftFalsy = false;
229+
if (leftValue.type === 'bool') isLeftFalsy = !leftValue.value;
230+
else if (leftValue.type === 'bigint') isLeftFalsy = leftValue.value === 0n;
231+
else if (leftValue.type === 'number') isLeftFalsy = leftValue.value === 0;
232+
else if (leftValue.type === 'string') isLeftFalsy = leftValue.value === '';
233+
else if (leftValue.type === 'undefined') isLeftFalsy = true;
234+
else isLeftFalsy = false; // Other types are generally truthy
235+
236+
if (isLeftFalsy) {
237+
stash.push(leftValue);
238+
} else {
239+
stash.push(rightValue);
240+
}
241+
} else {
242+
throw new Error(`Unsupported boolean operator: ${instr.symbol}`);
243+
}
244+
},
173245
};

src/cse-machine/py_types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ export interface BinOpInstr extends BaseInstr {
7272
symbol: string | TokenType
7373
}
7474

75+
export interface BoolOpInstr extends BaseInstr {
76+
symbol: TokenType;
77+
}
78+
7579
export interface AppInstr extends BaseInstr {
7680
numOfArgs: number
7781
srcNode: PyNode
@@ -100,4 +104,5 @@ export type Instr =
100104
| EnvInstr
101105
| ArrLitInstr
102106
| UnOpInstr
103-
| BinOpInstr
107+
| BinOpInstr
108+
| BoolOpInstr

0 commit comments

Comments
 (0)