def visitFnGetStream(self, ctx: YalangParser.FnGetStreamContext): l = self.visit(ctx.left) if l.typ != Expression.Type.ASYNC_CALL: raise VisitorException(ctx, "Cannot get stream from {}", l.typ) ident = ctx.right.text s = l.ins.get(ident, None) if s is None: s = l.outs.get(ident, None) if s is None: raise VisitorException(ctx, "Cannot get stream {}", ident) if self.debug: self.debug_info.append(s) return s
def visitStreamWrite(self, ctx: YalangParser.StreamWriteContext): s = self.visit(ctx.right) if s.typ != Expression.Type.STREAM: raise VisitorException(ctx, "Cannot write to {}", l.typ) if self.async_fn is None and not s.is_in(): raise VisitorException( ctx, "Cannot write to output of another function") if self.async_fn is not None and s in self.async_fn.ins.values(): raise VisitorException(ctx, "Cannot write to input within function") e = self.visit(ctx.left) if self.debug: self.debug_info.append(e) return s.write(e)
def visitIdentifier(self, ctx: YalangParser.IdentifierContext): ident = ctx.ID().getText() e = self.scope.get(ident, None) if e is None: raise VisitorException(ctx, "Undefined variable {}", ident) if self.debug: self.debug_info.append(e) return e
def visitReturnStmt(self, ctx: YalangParser.ReturnStmtContext): if not self.is_fn: raise VisitorException( ctx, "Return statement is allowed only in functions") e = self.visit(ctx.expression()) self.return_value = e if self.debug: self.debug_info.append(e) return e
def visitFnCall(self, ctx: YalangParser.FnCallContext): f = self.visit(ctx.callee) if f.typ != Expression.Type.FUNCTION: raise VisitorException(ctx, "variable is not callable") params = [self.visit(p) for p in ctx.params] r = f.call(ctx, params, self.async_calls) if self.debug: self.debug_info.append(r) return r
def visitUnaryMinus(self, ctx: YalangParser.UnaryMinusContext): expr = self.visit(ctx.expression()) if not expr.is_number(): raise VisitorException(ctx, "Unary Math on non-numeric value: -{}", expr) e = Expression('-' + expr.value, expr.typ) if self.debug: self.debug_info.append(e) return e
def visitStreamRead(self, ctx: YalangParser.StreamReadContext): s = self.visit(ctx.expression()) if s.typ != Expression.Type.STREAM: raise VisitorException(ctx, "Cannot read from {}", l.typ) if self.async_fn is None and s.is_in(): raise VisitorException( ctx, "Cannot read from input to another function") if self.async_fn is not None and s in self.async_fn.outs.values(): raise VisitorException(ctx, "Cannot read from output within function") try: e = s.read() except LoopExit as ex: raise VisitorException(ctx, "Deadlock detected") if e is None: raise VisitorException(ctx, "Attempted read from empty stream") if self.debug: self.debug_info.append(e) return e
def visitBinaryMath(self, ctx): op = ctx.op.text l = self.visit(ctx.left) r = self.visit(ctx.right) if not l.is_number() or not r.is_number(): raise VisitorException( ctx, "Binary Math on non-numeric values: {} {} {}", l.value, op, r.value) r = eval(l.value + op + r.value) e = Expression(str(r), l.typ) if self.debug: self.debug_info.append(e) return e
def __init__(self, ctx, scope, ins, args, outs, body): self.ctx = ctx if len(set(ins) & set(outs)) > 0: raise VisitorException( ctx, "Name clash between input and output streams") self.scope = scope self.ins = ins self.args = args self.outs = outs self.is_async = len(ins) > 0 or len(outs) > 0 self.body = body self.exception = None self.typ = self.Type.FUNCTION self.value = None
def call(self, call_ctx, params, async_calls): if len(params) != len(self.args): raise VisitorException(call_ctx, "function requires {} args, {} given", len(self.args), len(params)) scope = self.scope.copy() for k, v in zip(self.args, params): scope[k] = v if self.is_async: ac = AsyncCall(scope, self.ins, self.outs, self.body) ac.start(async_calls) return ac else: return call_fn(scope, self.body, async_calls=async_calls)
def visitCloseStmt(self, ctx: YalangParser.CloseStmtContext): s = self.visit(ctx.stream) if s.typ != Expression.Type.STREAM: raise VisitorException(ctx, "Cannot close {}", s.typ) s.write(EOS)