int arg_count_of_string( char* s, int len ) { char c = *s; if ( !is_id_alpha(c) ) return 1; if ( s[ len - 1 ] != ':' ) return 0; // an optimization fint argc = 1; for ( const char* ss = s + len - 3; // last is :, next-to-last is alpha ss > s; // do not need to look at first one --ss ) if (*ss == ':') ++argc; return argc; }
fint str_arg_count(const char* s, fint len) { assert(len > 0, "should have a positive length"); char c = *s; if (!is_id_alpha(c)) { return 1; } if ( s[ len-1 ] != ':' ) return 0; // an optimization fint argc = 1; for (const char* ss = s + len - 3; // last is :, next-to-last is alpha ss > s; // do not need to look at first one --ss ) { if (*ss == ':') { argc ++; } } return argc; }
fint str_arg_count(const char* s) { char c = *s++; assert(c != '\0', "shouldn't be testing the empty string"); if (!is_id_alpha(c)) { return 1; } fint argc = 0; for (;;) { c = *s++; if (c == '\0') { break; } else if (c == ':') { argc ++; } } return argc; }
Token* Scanner::get_token() { Token* t; if (tokens) { t = tokens->token; tokens = tokens->prev; } else { t = NULL; while (t == NULL) { fint c = get_char(); switch (c) { case EOF: depth = 0; t = new Token(Token::ACCEPT, line, column, sourceAddr()); break; case '\n': case '\r': if (depth <= 0 && !is_string_scanner()) { t = new Token(Token::ACCEPT, line, column - 1, sourceAddr() - 1); depth = 0; } break; case ' ': case '\t': case '\v': case '\b': case '\f': break; case '"': t = skip_comment(); break; case '(': depth ++; t = new Token(as_TokenType('('), line, column - 1, sourceAddr() - 1); break; case ')': depth --; t = new Token(as_TokenType(')'), line, column - 1, sourceAddr() - 1); break; case '[': depth ++; t = new Token(as_TokenType('['), line, column - 1, sourceAddr() - 1); break; case ']': depth --; t = new Token(as_TokenType(']'), line, column - 1, sourceAddr() - 1); break; case '.': t = read_dot(); break; case '\'': t = read_string(); break; case '\\': c = get_char(); if (c == '\n' || c == '\r') { // an escaped newline; ignore } else { push_char(c); c = '\\'; t = read_op(c); } break; case '{': t = new Token(Token::ANNOTATION_START, line, column - 1, sourceAddr() - 1); break; case '}': t = new Token(Token::ANNOTATION_END, line, column - 1, sourceAddr() - 1); break; default: if (is_digit(c) || c == '-') t = read_number(c); else if (is_id_alpha(c) || c == ':') t = read_name(c); else if (is_punct(c)) t = read_op(c); else t = TokenizingError("unknown character in input"); } } } if (t && PrintTokens) t->print(); return t; }
Token* Scanner::read_name(fint c) { Token::TokenType t; fint l = line; fint col = column - 1; const char* ss = sourceAddr() - 1; fint len; if (c == ':') { t = Token::ARG; len = 0; } else { t = c == '_' ? Token::PRIMNAME : Token::NAME; len = 1; buffer[0] = char(c); } while (c = get_char(), is_id_char(c)) { buffer[len++] = char(c); } if (c == ':' && (t == Token::NAME || t == Token::PRIMNAME)) { buffer[len++] = char(c); if (is_upper((fint)*buffer)) t = Token::CAPKEYWORD; else t = c == '_' ? Token::PRIMKEYWORD : Token::KEYWORD; } else { push_char(c); } buffer[len] = '\0'; if (t == Token::ARG && len == 0) { t = as_TokenType(':'); } else if (t == Token::NAME || t == Token::PRIMNAME) { c = get_char(); if (c == '.') { c = get_char(); push_char(c); if (is_id_alpha(c) || is_punct(c)) { t = Token::DELEGATE; } else { push_char('.'); } } else { push_char(c); } } if (strcmp(buffer, "self") == 0) { if (t == Token::NAME) { t = Token::SELF_TOKEN; } else { return TokenizingError( "using \"self\" as a parent name for a directed resend"); } } else if (strcmp(buffer, "resend") == 0) { if (t == Token::DELEGATE) { t = Token::RESEND_TOKEN; } else { return TokenizingError("not using \"resend\" in a resend"); } } String* s; if (t == Token::NAME || t == Token::PRIMNAME || t == Token::ARG || t == Token::DELEGATE || t == Token::KEYWORD || t == Token::PRIMKEYWORD || t == Token::CAPKEYWORD) { s = new String(copy_string(buffer)); } else { s = NULL; } return new Token(t, s, l, col, ss); }