func (b *block) exit() { if b.outer == nil { log.Crash("Cannot exit top-level block") } if b.outer.scope == b.scope { if b.outer.inner != b { log.Crash("Already exited block") } if b.inner != nil && b.inner.scope == b.scope { log.Crash("Exit of parent block without exit of child block") } } b.outer.inner = nil }
// Go invokes the function asynchronously. It returns the Call structure representing // the invocation. The done channel will signal when the call is complete by returning // the same Call object. If done is nil, Go will allocate a new channel. // If non-nil, done must be buffered or Go will deliberately crash. func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call { c := new(Call) c.ServiceMethod = serviceMethod c.Args = args c.Reply = reply if done == nil { done = make(chan *Call, 10) // buffered. } else { // If caller passes done != nil, it must arrange that // done has enough buffer for the number of simultaneous // RPCs that will be using that channel. If the channel // is totally unbuffered, it's best not to run at all. if cap(done) == 0 { log.Crash("rpc: done channel is unbuffered") } } c.Done = done if client.shutdown != nil { c.Error = client.shutdown _ = c.Done <- c // do not block return c } client.send(c) return c }
// Publish declares an named exported variable. This should be called from a // package's init function when it creates its Vars. If the name is already // registered then this will log.Crash. func Publish(name string, v Var) { mutex.Lock() defer mutex.Unlock() if _, existing := vars[name]; existing { log.Crash("Reuse of exported var name:", name) } vars[name] = v }
func (b *block) ChildScope() *Scope { if b.inner != nil && b.inner.scope == b.scope { log.Crash("Failed to exit child block before entering a child scope") } sub := b.enterChild() sub.offset = 0 sub.scope = &Scope{sub, 0} return sub.scope }
func (logger *base) Add(severity Severity, format string, v ...interface{}) { if logger.addFunc == nil { log.Crash("Tried to use base logger, which has no ability to output. Use descendants instead!") } if severity < logger.LogLevel { return } logger.addFunc(severity, format, v) }
func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) { switch decl := s.Decl.(type) { case *ast.BadDecl: // Do nothing. Already reported by parser. a.silentErrors++ case *ast.FuncDecl: if !a.block.global { log.Crash("FuncDecl at statement level") } case *ast.GenDecl: if decl.Tok == token.IMPORT && !a.block.global { log.Crash("import at statement level") } default: log.Crashf("Unexpected Decl type %T", s.Decl) } a.compileDecl(s.Decl) }
func (b *block) enterChild() *block { if b.inner != nil && b.inner.scope == b.scope { log.Crash("Failed to exit child block before entering another child") } sub := &block{ outer: b, scope: b.scope, defs: make(map[string]Def), offset: b.offset + b.numVars, } b.inner = sub return sub }
func (b *block) defineSlot(t Type, temp bool) *Variable { if b.inner != nil && b.inner.scope == b.scope { log.Crash("Failed to exit child block before defining variable") } index := -1 if !b.global || temp { index = b.offset + b.numVars b.numVars++ if index >= b.scope.maxVars { b.scope.maxVars = index + 1 } } v := &Variable{token.Position{}, index, t, nil} return v }
func main() { flag.Parse() // The counter is published as a variable directly. ctr := new(Counter) http.Handle("/counter", ctr) expvar.Publish("counter", ctr) http.Handle("/go/", http.HandlerFunc(FileServer)) http.Handle("/flags", http.HandlerFunc(FlagServer)) http.Handle("/args", http.HandlerFunc(ArgServer)) http.Handle("/go/hello", http.HandlerFunc(HelloServer)) http.Handle("/chan", ChanCreate()) http.Handle("/date", http.HandlerFunc(DateServer)) err := http.ListenAndServe(":12345", nil) if err != nil { log.Crash("ListenAndServe: ", err) } }
func main() { // read arguments listen_addr := flag.String("listen", "0.0.0.0:6667", "Port to listen for IRC connections on") log_file := flag.String("log-file", "/dev/stdout", "Where to write log files") flag.Parse() // Set up logging var outFile *os.File if *log_file == "/dev/stdout" { outFile = os.Stdout } else { var err os.Error outFile, err = os.Open(*log_file, os.O_WRONLY|os.O_CREAT, 0755) if err != nil { log.Crash("Oh noes!") } } logger = log.New(outFile, nil, "", log.Ldate|log.Ltime) listenAddress, err := net.ResolveTCPAddr(*listen_addr) if err != nil { logger.Log("failed creating listenAddress") } listener, err := net.ListenTCP("tcp", listenAddress) if err != nil { logger.Log("failed listening") } for { newConnection, err := listener.AcceptTCP() if err != nil { logger.Log("failed accepting TCP connection") } go StartGateway(newConnection) } }
func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) { var pc *uint switch s.Tok { case token.BREAK: l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select") if l == nil { return } pc = l.breakPC case token.CONTINUE: l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop") if l == nil { return } pc = l.continuePC case token.GOTO: l, ok := a.labels[s.Label.Name()] if !ok { pc := badPC l = &label{name: s.Label.Name(), desc: "unresolved label", gotoPC: &pc, used: s.Pos()} a.labels[l.name] = l } pc = l.gotoPC a.flow.putGoto(s.Pos(), l.name, a.block) case token.FALLTHROUGH: a.diag("fallthrough outside switch") return default: log.Crash("Unexpected branch token %v", s.Tok) } a.flow.put1(false, pc) a.push(func(v *Thread) { v.pc = *pc }) }
func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) { for _, spec := range decl.Specs { spec := spec.(*ast.ValueSpec) if spec.Values == nil { // Declaration without assignment if spec.Type == nil { // Parser should have caught log.Crash("Type and Values nil") } t := a.compileType(a.block, spec.Type) // Define placeholders even if type compile failed for _, n := range spec.Names { a.defineVar(n, t) } } else { // Declaration with assignment lhs := make([]ast.Expr, len(spec.Names)) for i, n := range spec.Names { lhs[i] = n } a.doAssign(lhs, spec.Values, decl.Tok, spec.Type) } } }
func (a *stmtCompiler) compile(s ast.Stmt) { if a.block.inner != nil { log.Crash("Child scope still entered") } notimpl := false switch s := s.(type) { case *ast.BadStmt: // Error already reported by parser. a.silentErrors++ case *ast.DeclStmt: a.compileDeclStmt(s) case *ast.EmptyStmt: // Do nothing. case *ast.LabeledStmt: a.compileLabeledStmt(s) case *ast.ExprStmt: a.compileExprStmt(s) case *ast.IncDecStmt: a.compileIncDecStmt(s) case *ast.AssignStmt: a.compileAssignStmt(s) case *ast.GoStmt: notimpl = true case *ast.DeferStmt: notimpl = true case *ast.ReturnStmt: a.compileReturnStmt(s) case *ast.BranchStmt: a.compileBranchStmt(s) case *ast.BlockStmt: a.compileBlockStmt(s) case *ast.IfStmt: a.compileIfStmt(s) case *ast.CaseClause: a.diag("case clause outside switch") case *ast.SwitchStmt: a.compileSwitchStmt(s) case *ast.TypeCaseClause: notimpl = true case *ast.TypeSwitchStmt: notimpl = true case *ast.CommClause: notimpl = true case *ast.SelectStmt: notimpl = true case *ast.ForStmt: a.compileForStmt(s) case *ast.RangeStmt: notimpl = true default: log.Crashf("unexpected ast node type %T", s) } if notimpl { a.diag("%T statment node not implemented", s) } if a.block.inner != nil { log.Crash("Forgot to exit child scope") } }
func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr { // mark marks a field that matches the selector name. It // tracks the best depth found so far and whether more than // one field has been found at that depth. bestDepth := -1 ambig := false amberr := "" mark := func(depth int, pathName string) { switch { case bestDepth == -1 || depth < bestDepth: bestDepth = depth ambig = false amberr = "" case depth == bestDepth: ambig = true default: log.Crashf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth) } amberr += "\n\t" + pathName[1:] } visited := make(map[Type]bool) // find recursively searches for the named field, starting at // type t. If it finds the named field, it returns a function // which takes an expr that represents a value of type 't' and // returns an expr that retrieves the named field. We delay // expr construction to avoid producing lots of useless expr's // as we search. // // TODO(austin) Now that the expression compiler works on // semantic values instead of AST's, there should be a much // better way of doing this. var find func(Type, int, string) func(*expr) *expr find = func(t Type, depth int, pathName string) func(*expr) *expr { // Don't bother looking if we've found something shallower if bestDepth != -1 && bestDepth < depth { return nil } // Don't check the same type twice and avoid loops if _, ok := visited[t]; ok { return nil } visited[t] = true // Implicit dereference deref := false if ti, ok := t.(*PtrType); ok { deref = true t = ti.Elem } // If it's a named type, look for methods if ti, ok := t.(*NamedType); ok { _, ok := ti.methods[name] if ok { mark(depth, pathName+"."+name) log.Crash("Methods not implemented") } t = ti.Def } // If it's a struct type, check fields and embedded types var builder func(*expr) *expr if t, ok := t.(*StructType); ok { for i, f := range t.Elems { var sub func(*expr) *expr switch { case f.Name == name: mark(depth, pathName+"."+name) sub = func(e *expr) *expr { return e } case f.Anonymous: sub = find(f.Type, depth+1, pathName+"."+f.Name) if sub == nil { continue } default: continue } // We found something. Create a // builder for accessing this field. ft := f.Type index := i builder = func(parent *expr) *expr { if deref { parent = a.compileStarExpr(parent) } expr := a.newExpr(ft, "selector expression") pf := parent.asStruct() evalAddr := func(t *Thread) Value { return pf(t).Field(t, index) } expr.genValue(evalAddr) return sub(expr) } } } return builder } builder := find(v.t, 0, "") if builder == nil { a.diag("type %v has no field or method %s", v.t, name) return nil } if ambig { a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr) return nil } return builder(v) }
func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr { // Save the original types of l.t and r.t for error messages. origlt := l.t origrt := r.t // XXX(Spec) What is the exact definition of a "named type"? // XXX(Spec) Arithmetic operators: "Integer types" apparently // means all types compatible with basic integer types, though // this is never explained. Likewise for float types, etc. // This relates to the missing explanation of named types. // XXX(Spec) Operators: "If both operands are ideal numbers, // the conversion is to ideal floats if one of the operands is // an ideal float (relevant for / and %)." How is that // relevant only for / and %? If I add an ideal int and an // ideal float, I get an ideal float. if op != token.SHL && op != token.SHR { // Except in shift expressions, if one operand has // numeric type and the other operand is an ideal // number, the ideal number is converted to match the // type of the other operand. if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() { r = r.convertTo(l.t) } else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() { l = l.convertTo(r.t) } if l == nil || r == nil { return nil } // Except in shift expressions, if both operands are // ideal numbers and one is an ideal float, the other // is converted to ideal float. if l.t.isIdeal() && r.t.isIdeal() { if l.t.isInteger() && r.t.isFloat() { l = l.convertTo(r.t) } else if l.t.isFloat() && r.t.isInteger() { r = r.convertTo(l.t) } if l == nil || r == nil { return nil } } } // Useful type predicates // TODO(austin) CL 33668 mandates identical types except for comparisons. compat := func() bool { return l.t.compat(r.t, false) } integers := func() bool { return l.t.isInteger() && r.t.isInteger() } floats := func() bool { return l.t.isFloat() && r.t.isFloat() } strings := func() bool { // TODO(austin) Deal with named types return l.t == StringType && r.t == StringType } booleans := func() bool { return l.t.isBoolean() && r.t.isBoolean() } // Type check var t Type switch op { case token.ADD: if !compat() || (!integers() && !floats() && !strings()) { a.diagOpTypes(op, origlt, origrt) return nil } t = l.t case token.SUB, token.MUL, token.QUO: if !compat() || (!integers() && !floats()) { a.diagOpTypes(op, origlt, origrt) return nil } t = l.t case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT: if !compat() || !integers() { a.diagOpTypes(op, origlt, origrt) return nil } t = l.t case token.SHL, token.SHR: // XXX(Spec) Is it okay for the right operand to be an // ideal float with no fractional part? "The right // operand in a shift operation must be always be of // unsigned integer type or an ideal number that can // be safely converted into an unsigned integer type // (§Arithmetic operators)" suggests so and 6g agrees. if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) { a.diagOpTypes(op, origlt, origrt) return nil } // The right operand in a shift operation must be // always be of unsigned integer type or an ideal // number that can be safely converted into an // unsigned integer type. if r.t.isIdeal() { r2 := r.convertTo(UintType) if r2 == nil { return nil } // If the left operand is not ideal, convert // the right to not ideal. if !l.t.isIdeal() { r = r2 } // If both are ideal, but the right side isn't // an ideal int, convert it to simplify things. if l.t.isIdeal() && !r.t.isInteger() { r = r.convertTo(IdealIntType) if r == nil { log.Crashf("conversion to uintType succeeded, but conversion to idealIntType failed") } } } else if _, ok := r.t.lit().(*uintType); !ok { a.diag("right operand of shift must be unsigned") return nil } if l.t.isIdeal() && !r.t.isIdeal() { // XXX(Spec) What is the meaning of "ideal >> // non-ideal"? Russ says the ideal should be // converted to an int. 6g propagates the // type down from assignments as a hint. l = l.convertTo(IntType) if l == nil { return nil } } // At this point, we should have one of three cases: // 1) uint SHIFT uint // 2) int SHIFT uint // 3) ideal int SHIFT ideal int t = l.t case token.LOR, token.LAND: if !booleans() { return nil } // XXX(Spec) There's no mention of *which* boolean // type the logical operators return. From poking at // 6g, it appears to be the named boolean type, NOT // the type of the left operand, and NOT an unnamed // boolean type. t = BoolType case token.ARROW: // The operands in channel sends differ in type: one // is always a channel and the other is a variable or // value of the channel's element type. log.Crash("Binary op <- not implemented") t = BoolType case token.LSS, token.GTR, token.LEQ, token.GEQ: // XXX(Spec) It's really unclear what types which // comparison operators apply to. I feel like the // text is trying to paint a Venn diagram for me, // which it's really pretty simple: <, <=, >, >= apply // only to numeric types and strings. == and != apply // to everything except arrays and structs, and there // are some restrictions on when it applies to slices. if !compat() || (!integers() && !floats() && !strings()) { a.diagOpTypes(op, origlt, origrt) return nil } t = BoolType case token.EQL, token.NEQ: // XXX(Spec) The rules for type checking comparison // operators are spread across three places that all // partially overlap with each other: the Comparison // Compatibility section, the Operators section, and // the Comparison Operators section. The Operators // section should just say that operators require // identical types (as it does currently) except that // there a few special cases for comparison, which are // described in section X. Currently it includes just // one of the four special cases. The Comparison // Compatibility section and the Comparison Operators // section should either be merged, or at least the // Comparison Compatibility section should be // exclusively about type checking and the Comparison // Operators section should be exclusively about // semantics. // XXX(Spec) Comparison operators: "All comparison // operators apply to basic types except bools." This // is very difficult to parse. It's explained much // better in the Comparison Compatibility section. // XXX(Spec) Comparison compatibility: "Function // values are equal if they refer to the same // function." is rather vague. It should probably be // similar to the way the rule for map values is // written: Function values are equal if they were // created by the same execution of a function literal // or refer to the same function declaration. This is // *almost* but not quite waht 6g implements. If a // function literals does not capture any variables, // then multiple executions of it will result in the // same closure. Russ says he'll change that. // TODO(austin) Deal with remaining special cases if !compat() { a.diagOpTypes(op, origlt, origrt) return nil } // Arrays and structs may not be compared to anything. switch l.t.(type) { case *ArrayType, *StructType: a.diagOpTypes(op, origlt, origrt) return nil } t = BoolType default: log.Crashf("unknown binary operator %v", op) } desc, ok := binOpDescs[op] if !ok { desc = op.String() + " expression" binOpDescs[op] = desc } // Check for ideal divide by zero switch op { case token.QUO, token.REM: if r.t.isIdeal() { if (r.t.isInteger() && r.asIdealInt()().IsZero()) || (r.t.isFloat() && r.asIdealFloat()().IsZero()) { a.diag("divide by zero") return nil } } } // Compile expr := a.newExpr(t, desc) switch op { case token.ADD: expr.genBinOpAdd(l, r) case token.SUB: expr.genBinOpSub(l, r) case token.MUL: expr.genBinOpMul(l, r) case token.QUO: expr.genBinOpQuo(l, r) case token.REM: expr.genBinOpRem(l, r) case token.AND: expr.genBinOpAnd(l, r) case token.OR: expr.genBinOpOr(l, r) case token.XOR: expr.genBinOpXor(l, r) case token.AND_NOT: expr.genBinOpAndNot(l, r) case token.SHL: if l.t.isIdeal() { lv := l.asIdealInt()() rv := r.asIdealInt()() const maxShift = 99999 if rv.Cmp(bignum.Int(maxShift)) > 0 { a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift) expr.t = nil return nil } val := lv.Shl(uint(rv.Value())) expr.eval = func() *bignum.Integer { return val } } else { expr.genBinOpShl(l, r) } case token.SHR: if l.t.isIdeal() { lv := l.asIdealInt()() rv := r.asIdealInt()() val := lv.Shr(uint(rv.Value())) expr.eval = func() *bignum.Integer { return val } } else { expr.genBinOpShr(l, r) } case token.LSS: expr.genBinOpLss(l, r) case token.GTR: expr.genBinOpGtr(l, r) case token.LEQ: expr.genBinOpLeq(l, r) case token.GEQ: expr.genBinOpGeq(l, r) case token.EQL: expr.genBinOpEql(l, r) case token.NEQ: expr.genBinOpNeq(l, r) case token.LAND: expr.genBinOpLogAnd(l, r) case token.LOR: expr.genBinOpLogOr(l, r) default: log.Crashf("Compilation of binary op %v not implemented", op) } return expr }