text:
// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"testing"
)

func benchmarkExporter(times int, b *testing.B) {
	input := []string{
		"foo1:2|c",
		"foo2:3|g",
		"foo3:200|ms",
		"foo4:100|c|#tag1:bar,tag2:baz",
		"foo5:100|c|#tag1:bar,#tag2:baz",
		"foo6:100|c|#09digits:0,tag.with.dots:1",
		"foo10:100|c|@0.1|#tag1:bar,#tag2:baz",
		"foo11:100|c|@0.1|#tag1:foo:bar",
		"foo15:200|ms:300|ms:5|c|@0.1:6|g\nfoo15a:1|c:5|ms",
		"some_very_useful_metrics_with_quite_a_log_name:13|c",
	}
	bytesInput := make([]string, len(input)*times)
	for run := 0; run < times; run++ {
		for i := 0; i < len(input); i++ {
			bytesInput[run*len(input)+i] = fmt.Sprintf("run%d%s", run, input[i])
		}
	}
	for n := 0; n < b.N; n++ {
		l := StatsDUDPListener{}
		// there are more events than input lines, need bigger buffer
		events := make(chan Events, len(bytesInput)*times*2)

		for i := 0; i < times; i++ {
			for _, line := range bytesInput {
				l.handlePacket([]byte(line), events)
			}
		}
	}
}

func BenchmarkExporter1(b *testing.B) {
	benchmarkExporter(1, b)
}
func BenchmarkExporter5(b *testing.B) {
	benchmarkExporter(5, b)
}
func BenchmarkExporter50(b *testing.B) {
	benchmarkExporter(50, b)
}

gha_language: Go

extension: go


text:
# cppunit OE build file
# Copyright (C) 2005, Koninklijke Philips Electronics NV.  All Rights Reserved
# Released under the MIT license (see packages/COPYING)

DESCRIPTION = "Unit Testing Library for C++"
HOMEPAGE = "http://cppunit.sourceforge.net/"
LICENSE = "LGPL"
SECTION = "devel"
PR = "r1"

SRC_URI = "${SOURCEFORGE_MIRROR}/cppunit/cppunit-${PV}.tar.gz"

inherit autotools binconfig

CXXFLAGS_powerpc += "-lstdc++"

SRC_URI[md5sum] = "bd30e9cf5523cdfc019b94f5e1d7fd19"
SRC_URI[sha256sum] = "ac28a04c8e6c9217d910b0ae7122832d28d9917fa668bcc9e0b8b09acb4ea44a"

license: MIT

repository: overo/overo-oe-natty

license_type: permissive

repo_name: overo/overo-oe-natty

branch_name: HEAD

extension: bb


text:
@InProceedings{ahmed16,
  title = {Exact and Estimation of Local Edge-centric Graphlet Counts},
  author = {Ahmed, Nesreen K. and Willke, Theodore L. and Rossi, Ryan A.},
  abstract = {Graphlets represent small induced subgraphs and are becoming increasingly important for
	a variety of applications. Despite the importance of the local graphlet problem, existing
	work focuses mainly on counting graphlets globally over the entire graph. These global
	counts have been used for tasks such as graph classification as well as for understanding and
	summarizing the fundamental structural patterns in graphs. In contrast, this work proposes
	a flexible, efficient, and scalable parallel framework for the more challenging problem of
	counting graphlets locally for a given edge or set of edges.The local graphlet counts provide
	a topologically rigorous characterization of the local structure surrounding an edge. The
	aim of this work is to obtain the count of every graphlet of size  $k \in \{3, 4 \} $ for each edge.
	The framework gives rise to efficient, parallel, and accurate unbiased estimation methods as
	well as exact graphlet algorithms for counting graphlets locally. Experiments demonstrate
	the effectiveness of the proposed exact and estimation methods.},
  pages = {1--17},
}

repository: mreid/papersite

repo_name: mreid/papersite

branch_name: refs/heads/master

gha_license_id: MIT

gha_language: TeX

extension: bib


text:
/******************************************************************************/
/*                                                                            */
/* Copyright (c) 2010, 2014 Sylwester Wysocki <sw143@wp.pl>                   */
/*                                                                            */
/* Permission is hereby granted, free of charge, to any person obtaining a    */
/* copy of this software and associated documentation files (the "Software"), */
/* to deal in the Software without restriction, including without limitation  */
/* the rights to use, copy, modify, merge, publish, distribute, sublicense,   */
/* and/or sell copies of the Software, and to permit persons to whom the      */
/* Software is furnished to do so, subject to the following conditions:       */
/*                                                                            */
/* The above copyright notice and this permission notice shall be included in */
/* all copies or substantial portions of the Software.                        */
/*                                                                            */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        */
/* DEALINGS IN THE SOFTWARE.                                                  */
/*                                                                            */
/******************************************************************************/

//
// Purpose: Generate HTML documentation from comments
//          inside source code.
//

#include "AutoDoc.h"
#include "Diagram.h"
#include <Tegenaria/Str.h>

#ifdef WIN32
# include <io.h>
#endif

using namespace Tegenaria;

int ListComponents(SourceInfo *pi, vector<SourceInfo> &comps);

#define HTML_PRE_STYLE "width:720px;"        \
                       "background:#eee;"    \
                       "border-style:solid;" \
                       "border-color:#888;"  \
                       "border-width:1px;"   \
                       "padding: 8px;"
//
//
//

static string AutoDocHighlightCode(string code)
{
  string oldStr;
  string newStr;

  const char *types[] =
  {
    "int", "double", "float", "vector", "string", "set", "map", "void",
    "stack", "const", "unsigned", "signed", "char", "int64_t", "int32_t",
    "int8_t", "uint64_t", "uint32_t", "uint16_t", "uint8_t", "int16_t",
    "bool", "DWORD", "HANDLE", "BOOL", NULL
  };

  code = " " + code + " ";

  for (int i = 0; types[i]; i++)
  {
    oldStr = string(" ") + types[i] + string(" ");
    newStr = string(" ") + types[i] + string(" ");
    StrReplaceString(code, oldStr.c_str(), newStr.c_str());
  }

  return code.substr(1, code.size() - 1);
}

//
//
//

static string AutoDocFormatFunctionProto(FunctionInfo *fi)
{
  string rv = "";

  vector<string> args;
  vector<string> argTypes;
  vector<string> argNames;

  int argTypeLengthMax = 0;

  rv += StrNormalizeWhiteSpaces(fi -> return_);

  if (!rv.empty())
  {
    rv += " ";
  }

  rv += StrNormalizeWhiteSpaces(fi -> name_);
  rv += "\n";
  rv += "(\n";

  StrTokenize(args, fi -> args_, ",()");

  //
  // Remove empty tokens from args[].
  //

  for (vector<string>::iterator it = args.begin(); it != args.end(); )
  {
    (*it) = StrNormalizeWhiteSpaces(*it);

    if (it -> empty())
    {
      it = args.erase(it);
    }
    else
    {
      it ++;
    }
  }

  //
  // Split args[] into type and variable name.
  //

  for (int i = 0; i < args.size(); i++)
  {
    string type;
    string name;

    //
    // Find position of last whitespace.
    //

    int lastSpaceIdx = -1;

    for (int j = 0; j < args[i].size(); j++)
    {
      if (isspace(args[i][j]))
      {
        lastSpaceIdx = j;
      }
    }

    if (lastSpaceIdx == -1)
    {
      //
      // Only typename found.
      //

      type = args[i];
      name = "";
    }
    else
    {
      //
      // Found typename and variable name.
      // Split them.
      //

      while(lastSpaceIdx < args[i].size() -1 &&
                (args[i][lastSpaceIdx] == '*') || isspace(args[i][lastSpaceIdx]))
      {
        lastSpaceIdx ++;
      }

      type = StrNormalizeWhiteSpaces(args[i].substr(0, lastSpaceIdx));
      name = StrNormalizeWhiteSpaces(args[i].substr(lastSpaceIdx));
    }

    //
    // Save splitted type and variable name.
    //

    argTypes.push_back(type);
    argNames.push_back(name);

    //
    // Count maximum type length.
    //

    if (type.size() > argTypeLengthMax)
    {
      argTypeLengthMax = type.size();
    }
  }

  //
  // Put args list.
  //

  for (int i = 0; i < args.size(); i++)
  {
    rv += "  ";
    rv += argTypes[i];

    for (int j = 0; j < argTypeLengthMax - argTypes[i].size() + 1; j++)
    {
      rv += " ";
    }

    rv += argNames[i];

    if (i < args.size() - 1)
    {
      rv += ",\n";
    }
    else
    {
      rv += "\n";
    }
  }

  rv += ");";

  rv = StrEncodeToHtml(rv, 0); //STR_HTML_NON_BREAK_SPACES);
  rv = AutoDocHighlightCode(rv);

  return rv;
}

//
// Parse #pragma qcbuild_xxx(parameter) macro.
//
// TODO: Handle multiple parameters.
//

static int AutoDocParseQCBuildPragma(QCBuildPragma *pragmaInfo, string line)
{
  int exitCode = -1;

  vector<string> args;

  char *buf = (char *) line.c_str();

  char *cmd       = NULL;
  char *argsBegin = NULL;
  char *argsEnd   = NULL;
  char *argsRaw   = NULL;

  cmd       = strstr(buf, "qcbuild_");
  argsBegin = strchr(buf, '(');

  for (int i = 0; buf[i]; i++)
  {
    if (buf[i] == ')')
    {
      argsEnd = buf + i;
    }
  }

  FAILEX(cmd == NULL,       "ERROR: Missing 'qcbuild_' prefix in #pragma macro '%s'.\n", line.c_str());
  FAILEX(argsBegin == NULL, "ERROR: Missing '(' in #pragma macro '%s'.\n", line.c_str());
  FAILEX(argsEnd == NULL,   "ERROR: Missing ')' in #pragma macro '%s'.\n", line.c_str());

  argsBegin[0] = 0;
  argsEnd[0]   = 0;
  argsRaw      = argsBegin + 1;

  StrTokenize(args, argsRaw, ",", "\"");

  pragmaInfo -> cmd_ = cmd;
  pragmaInfo -> args_.resize(1);
  pragmaInfo -> args_ = args;

  DBG_MSG("Decoded [%s][%s] pragma command.\n", cmd, argsRaw);

  //
  // Error handler.
  //

  exitCode = 0;

  fail:

  return exitCode;
}

//
// Compare source files by number of functions inside.
//

static bool CompareSourceByNumberOfFunctions(const SourceFile &sf1,
                                                 const SourceFile &sf2)
{
  return sf1.functions_.size() > sf2.functions_.size();
}

//
// Generate list of functions inside given C/C++ source file.
//
// sourceFile - pointer to SourceFile struct to collect parsed info (OUT).
// fname      - name of C/C++ file to search (IN).
//
// RETURNS: 0 if OK.
//

int CollectFunctionsFromCSource(SourceFile *sourceFile, const char *fname, int privateMode)
{
  DBG_ENTER("CollectFunctionsFromCSource");

  int exitCode = -1;

  int goOn = 1;

  int deep = 0;

  int tokenId     = -1;
  int lastTokenId = -1;

  int eolTriggered = 0;

  vector<FunctionInfo> &fi = sourceFile -> functions_;

  string namespaceAtDeep[MAX_DEEP + 1];
  string token;
  string lastToken;
  string lastComment;
  string lastArgs;

  string lastIdent;
  string lastLastIdent;

  string returnType;
  string args;

  string currentNamespace;

  int privateAtDeep[MAX_DEEP + 1]    = {0};
  int functionIdAtDeep[MAX_DEEP + 1] = {0};

  FunctionInfo fiEntry;

  DBG_MSG("Assigning [%s]...\n", fname);

  sourceFile -> name_ = fname;

  fiEntry.fname_ = fname;

  //
  // Open source file.
  //

  FILE *f = fopen(fname, "rt");

  FAILEX(f == NULL, "ERROR: Cannot open file '%s'.\n", fname);

  //
  // Init functionIdAtDeep[] array.
  // We're not inside any function at the begin.
  //

  for (int i = 0; i < MAX_DEEP; i++)
  {
    functionIdAtDeep[i] = -1;
  }

  //
  // Scan file.
  //

  DEBUG3("CollectFunctionsFromCSource : Initing scanner...\n");

  ScanInit(f);

  while(goOn)
  {
    int visible = 1;

    tokenId = ScanPopToken(token);

    //
    // Hide content when inside private mode.
    //

    if (privateAtDeep[deep] == 1)
    {
      visible = 0;
    }

    //
    // Determine are we inside top level deep in current namespace.
    // For example:
    //
    // namespace X
    // {
    //   // top level for X namespace (level 0)
    //
    //   void f()
    //   {
    //     // level 1
    //     struct MyData =
    //     {
    //       // level 2
    //     }
    //   }
    // }
    //
    //
    //

    int isTopLevel = 0;

    if (deep == 0 || !namespaceAtDeep[deep].empty())
    {
      isTopLevel = 1;
    }

    DBG_MSG("[%d][%s][%s]\n", deep, GetTokenName(tokenId), token.c_str());

    if (!args.empty())
    {
      args += token;
    }

    switch(tokenId)
    {
      //
      // End of file.
      //

      case TOKEN_EOF:
      {
        goOn = 0;

        break;
      }

      //
      // TOKEN_IDENT
      //

      case TOKEN_IDENT:
      {
        lastLastIdent = lastIdent;
        lastIdent     = token;

        break;
      }

      //
      // Single EOL.
      // Reset comments.
      //

      case TOKEN_EOL:
      {
        eolTriggered = 1;

        break;
      }

      //
      // Comment. Collect comment.
      //

      case TOKEN_COMMENT:
      {
        if (eolTriggered)
        {
          eolTriggered = 0;

          lastComment.clear();
        }

        if (lastTokenId == TOKEN_COMMENT
                || lastTokenId == TOKEN_WHITE
                    || lastTokenId == TOKEN_EOL)
        {
          lastComment += "\n";
          lastComment += ' ';
          lastComment += token.substr(2);
        }
        else
        {
          lastComment += ' ';
          lastComment += token.substr(2);
        }

        break;
      }

      //
      // '('.
      // Probably begin of function arguments.
      //

      case TOKEN_PARENT_BEGIN:
      {
        if (isTopLevel)
        {
          if (fiEntry.return_.empty() && fiEntry.name_.empty())
          {
            fiEntry.return_ = returnType;
            fiEntry.name_   = lastToken;

            DBG_MSG("Argument's begin. Saved identifier [%s].\n", lastToken.c_str());
            DBG_MSG("Argument's begin. Saved return [%s].\n", returnType.c_str());

            returnType = "";
            args       = "(";
          }
          else
          {
            DBG_MSG("Skipped false function args. Probably constructor init list found.\n");
          }
        }

        break;
      }

      //
      // ')'.
      // End of arguments.
      //

      case TOKEN_PARENT_END:
      {
        DBG_MSG("Argument's end. Saved args [%s].\n", args.c_str());

        if (fiEntry.args_.empty())
        {
          fiEntry.args_ = args;
        }

        args.clear();

        break;
      }

      //
      // Block begin.
      // If found in global space it's probably function declaration.
      //

      case TOKEN_BLOCK_BEGIN:
      {
        //
        // Namespace body begin.
        //

        if (lastLastIdent == "namespace")
        {
          DBG_MSG("Entered namespace [%s].\n", lastIdent.c_str());

          namespaceAtDeep[deep + 1] = lastIdent;

          currentNamespace = lastIdent;
        }

        //
        // Function body begin.
        // Function can be started at top level in given namespace.
        //

        else if (isTopLevel && fiEntry.name_.empty() == 0 && fiEntry.args_.empty() == 0)
        {
          if (visible)
          {
            fiEntry.comment_ = StrEncodeToHtml(lastComment, STR_HTML_NON_BREAK_SPACES);

            //
            // Push recognized function to list.
            //

            DBG_MSG("Pushed function [%s][%s][%s]...\n",
                        fiEntry.return_.c_str(), fiEntry.name_.c_str(),
                            fiEntry.args_.c_str());

            fi.push_back(fiEntry);

            functionIdAtDeep[deep + 1] = fi.size() - 1;
          }

          //
          // Clear function's description struct.
          // We're collecting another function from zero.
          //

          lastComment.clear();

          fiEntry.return_.clear();
          fiEntry.args_.clear();
          fiEntry.comment_.clear();
          fiEntry.name_.clear();
        }

        deep ++;

        returnType = "";

        break;
      }

      //
      // '}'.
      //
      // Control deep level. Function declarations are possible
      // only in deep=0 (global space) or in deep=1 as inline class/struct.
      //

      case TOKEN_BLOCK_END:
      {
        lastComment.clear();
        returnType.clear();

        functionIdAtDeep[deep] = -1;

        if (!namespaceAtDeep[deep].empty())
        {
          DBG_MSG("Leaved namespace [%s].\n", namespaceAtDeep[deep].c_str());

          namespaceAtDeep[deep].clear();
        }

        for (int i = deep; i < MAX_DEEP; i++)
        {
          privateAtDeep[i] = 0;
        }

        deep --;

        break;
      }

      //
      // ';' or C macro.
      //

      case TOKEN_SEMICOLON:
      case TOKEN_MACRO:
      {
        DBG_MSG2("[TOKEN_SEMICOLON]: Clearing return type...\n");

        fiEntry.name_.clear();
        fiEntry.args_.clear();
        fiEntry.return_.clear();

        args.clear();
        returnType.clear();
        lastComment.clear();

        if (tokenId == TOKEN_MACRO
                && strstr(token.c_str(), "#pragma")
                    && strstr(token.c_str(), "qcbuild_"))
        {
          QCBuildPragma pragmaInfo;

          FAIL(AutoDocParseQCBuildPragma(&pragmaInfo, token));

          //
          // Dispatch to proper command.
          //

          if (pragmaInfo.cmd_ == "qcbuild_set_private")
          {
            //
            // qcbuild_set_private(bool)
            // Mark current namespace as private (not visible in public doc).
            // If called inside global space it makes whole source file
            // unvisible for public.
            //

            if ((pragmaInfo.args_.size() == 1) && (pragmaInfo.args_[0] == "1"))
            {
              for (int i = deep; i < MAX_DEEP; i++)
              {
                privateAtDeep[i] = 1;

                //
                // Remove current function if any.
                //

                if ((functionIdAtDeep[deep] != -1)
                        && (functionIdAtDeep[deep] == (fi.size() - 1)))
                {
                  FunctionInfo fiEntry = fi[fi.size() - 1];

                   DBG_MSG("Rolled back function [%s][%s][%s]...\n",
                               fiEntry.return_.c_str(), fiEntry.name_.c_str(),
                                   fiEntry.args_.c_str());

                   fi.resize(fi.size() - 1);
                }
              }
            }
          }
          else if (pragmaInfo.cmd_ == "qcbuild_set_file_title")
          {
            //
            // qcbuild_set_file_title(title)
            // Set title for current source file.
            //

            if (pragmaInfo.args_.size() == 1)
            {
              sourceFile -> title_ = pragmaInfo.args_[0];

              DBG_MSG("Set file title to [%s] for file [%s].\n",
                          sourceFile -> title_.c_str(), fname);
            }
          }
          else
          {
            Fatal("ERROR: Unknown pragma command at '%s'.\n", token.c_str());
          }
        }

        break;
      }
    }

    //
    // Collect return type before function prototype.
    //

    if (lastTokenId != TOKEN_COMMENT
            && lastTokenId != TOKEN_SEMICOLON
                && tokenId != TOKEN_SEMICOLON
                    && lastTokenId != TOKEN_BLOCK_END
                        && lastTokenId != TOKEN_BLOCK_BEGIN
                            && lastTokenId != TOKEN_MACRO)
    {
      returnType += lastToken;
    }

    //
    // Save last token.
    //

    lastToken   = token;
    lastTokenId = tokenId;
  }

  //
  // Generate title from source file name in public mode.
  //

  if (privateMode == 0 && sourceFile -> title_.empty())
  {
    int dotIdx = sourceFile -> name_.find('.');

    if (dotIdx != string::npos)
    {
      sourceFile -> title_ = sourceFile -> name_.substr(0, dotIdx);
    }
    else
    {
      sourceFile -> title_ = sourceFile -> name_;
    }
  }

  //
  // Clean up.
  //

  exitCode = 0;

  fail:

  if (exitCode)
  {
    Error("ERROR: Cannot collect functions from '%s' source.\n"
              "Error code is : %d.\n", fname, GetLastError());
  }

  if (f)
  {
    fclose(f);
  }

  DBG_LEAVE("CollectFunctionsFromCSource");

  return exitCode;
}

//
// Generate HTML code to render 2 columns row:
//
//

//   lvalue
//   rvalue
//

//
// f      - C stream, where to write generated HTML code (e.g. stdout) (IN).
// lvalue - content for left side column ('legend') (IN).
// rvalue - content for right side column ('legend') (IN).
//

void HtmlPrintRow(FILE *f, const char *lvalue, const char *rvalue)
{
  static int rowSwap = 1;

  string rvalueHtml = StrEncodeToHtml(rvalue);

  fprintf
  (
    f,

    /* Begin of row - put >>row color<< here*/
    "
"

      /* First column  - put >>lvalue<< here */
      ""
        "%s"
      "	"

      /* Second column - put >>rvalue<< here*/
      ""
        "%s"
      "	"

    /* End of row */
    "
",

    rowSwap ? "#ddd" : "#eee",
    lvalue,
    rvalueHtml.c_str()
  );

  rowSwap = !rowSwap;
}

//
// Load content of given file and put it as HTML data
// on given C stream.
// If file doesn't exist no data written to stream.
//
// f     - C stream, where to write HTML data (e.g. stdout) (IN).
// fname - file name to load (e.g. README) (IN).
// title - optional title to put at top of html data (IN/OPT).
//
// RETURNS: 0 if OK.
//

int HtmlPutFile(FILE *f, const char *fname, const char *title = NULL)
{
  int exitCode = -1;

  char *content = NULL;

  string contentHtml;

  //
  // Check args.
  //

  FAILEX(f == NULL, "ERROR: 'f' stream cannot be NULL in HtmlPutFile.\n");
  FAILEX(fname == NULL, "ERROR: 'fname' cannot be NULL in HtmlPutFile.\n");

  //
  // Load file.
  //

  content = FileLoad(fname);

  FAIL(content == NULL);

  //
  // Change CR+LF to LF.
  //

  StrRemoveChar(content, 13);

  //
  // Encode special chars into html.
  //

  contentHtml = content;

  StrReplaceString(contentHtml, "<", "&lt");
  StrReplaceString(contentHtml, ">", "&gt");

  //
  // Put encoded content to output C stream.
  //

  if (title)
  {
    fprintf(f, "
%s
\n", title);
  }

  fprintf(f, "
%s
\n", HTML_PRE_STYLE, contentHtml.c_str());

  //
  // Clean up.
  //

  exitCode = 0;

  fail:

  if (content)
  {
    free(content);
  }

  return exitCode;
}

//
// Collect info about every source files inside component.
//
// sourceFiles - generated table with descriptions for every source files
//               inside comopnent. (OUT).
//
// si          - description of one component to analyze (IN).
// privateMode - show private code too if set to 1 (IN).
//
// RETURNS: 0 if OK.
//

int CollectSourceFiles(vector<SourceFile> &sourceFiles, SourceInfo *si, int privateMode)
{
  DBG_ENTER("CollectSourceFiles");

  int exitCode = -1;

  vector<string> files;

  //
  // Tokenize CXXSRC variable into list of source files.
  //

  DEBUG3("CollectSourceFiles : Tokenizing CXXSRC for [%s].\n", si -> get("TITLE"));

  StrTokenize(files, si -> get("CXXSRC"));

  //
  // Collect all functions in every source files.
  //

  DEBUG3("CollectSourceFiles : Parsing source files for [%s].\n", si -> get("TITLE"));

  for (int i = 0; i < files.size(); i++)
  {
    SourceFile sf;

    DEBUG3("CollectSourceFiles : Parsing file [%s].\n", files[i].c_str());

    CollectFunctionsFromCSource(&sf, files[i].c_str(), privateMode);

    sourceFiles.push_back(sf);
  }

  //
  // Sort source files order by number of functions.
  //

  if (sourceFiles.size() > 0)
  {
    DEBUG3("CollectSourceFiles : Sorting source files for [%s].\n", si -> get("TITLE"));

    sort(sourceFiles.begin(), sourceFiles.end(), CompareSourceByNumberOfFunctions);
  }

  //
  // Error handler.
  //

  exitCode = 0;

  fail:

  DBG_LEAVE("CollectSourceFiles");

  return exitCode;
}

//
// Generate HTML documentation for given component.
//
// f  - C stream, where to print generated HTML (eg. stdout) (IN).
// si - Source info struct describing given component (IN).
//
// RETURNS: 0 if OK.
//

int GenerateHtmlFromSourceInfo(FILE *f, SourceInfo *si, int privateMode)
{
  int exitCode = -1;

  vector<SourceFile> sourceFiles;

  const char *title = NULL;

  //
  // Check args.
  //

  FAILEX(f == NULL, "ERROR: File stream cannot be NULL in GenerateHtmlFromSourceInfo.\n");
  FAILEX(si == NULL, "ERROR: Source info cannot be NULL in GenerateHtmlFromSourceInfo.\n");

  //
  // Print header table first.
  //

  fprintf(f, "
");
  {
    HtmlPrintRow(f, "Title:",       si -> get("TITLE"));
    HtmlPrintRow(f, "Type:",        si -> get("TYPE"));
    HtmlPrintRow(f, "Author(s):",   si -> get("AUTHOR"));
    HtmlPrintRow(f, "Copyright:",   si -> get("COPYRIGHT"));
    HtmlPrintRow(f, "License:",     si -> get("LICENSE"));
    HtmlPrintRow(f, "Purpose:",     si -> get("PURPOSE"));
    HtmlPrintRow(f, "Description:", si -> get("DESC"));

    if (privateMode)
    {
      HtmlPrintRow(f, "Sources:", si -> get("CXXSRC"));
    }

    HtmlPrintRow(f, "Dependences:", si -> get("DEPENDS"));
    HtmlPrintRow(f, "Used by:    ", si -> get("USED_BY"));
  }
  fprintf(f, "
");

  //
  // Collect all functions in every source files.
  //

  FAIL(CollectSourceFiles(sourceFiles, si, privateMode));

  //
  // Generate table of content with list of functions:
  //
  // function1
  // function2
  // function3
  // ...
  //

  if (sourceFiles.size() > 0)
  {
    fprintf(f, "
");

    fprintf(f, "
Functions list:
\n");

    title = si -> get("TITLE");

    for (int i = 0; i < sourceFiles.size(); i++)
    {
      vector<FunctionInfo> &fi = sourceFiles[i].functions_;

      if (fi.size() > 0)
      {
        fprintf(f, "
");
        {
          //
          // Source file div (container).
          //

          if (privateMode)
          {
            fprintf(f, "%s
\n", sourceFiles[i].name_.c_str());

            if (!sourceFiles[i].title_.empty())
            {
              fprintf(f, "(%s)
\n", sourceFiles[i].title_.c_str());
            }
          }
          else
          {
            fprintf(f, "%s
\n", sourceFiles[i].title_.c_str());
          }

          for (int j = 0; j < fi.size(); j++)
          {
            fprintf(f, "%s
\n", title, fi[j].name_.c_str(), i, fi[j].name_.c_str());
          }
        }
        fprintf(f, "
");
      }
    }

    fprintf(f, "
");
  }

  //
  // Put README file if exists.
  //

  HtmlPutFile(f, "README", "README:");
  HtmlPutFile(f, "TODO", "TODO:");
  HtmlPutFile(f, "CHANGELOG", "CHANGELOG:");

  //
  // Put function's descriptions retrieved from
  // comments before every function.
  //

  if (sourceFiles.size() > 0)
  {
    fprintf(f, "
Functions protos:
\n");

    for (int i = 0; i < sourceFiles.size(); i++)
    {
      vector<FunctionInfo> &fi = sourceFiles[i].functions_;

      if (fi.size() > 0)
      {
        const char *fname = sourceFiles[i].name_.c_str();

        fprintf(f, "
%s
\n", title, fname, fname);

        for (int j = 0; j < fi.size(); j++)
        {
          //
          // Function name.
          //

          fprintf(f, "\n", title, fi[j].name_.c_str(), i);

          //
          // HTML tag to link it from table of content.
          //

          fprintf(f, "
%s
\n", title, fi[j].name_.c_str(), i, fi[j].name_.c_str());

          //
          // Function prototype.
          //

          fprintf(f, "
%s
",
                      HTML_PRE_STYLE, AutoDocFormatFunctionProto(&fi[j]).c_str());

          //
          // Function description retrieved from comment in source code.
          //

          if (fi[j].comment_.size() > 16)
          {
            string comment = fi[j].comment_;

//            comment = StrReplaceString(comment, "TIP", "TIP");
//            comment = StrReplaceString(comment, "WARNING", "WARNING");

            fprintf(f, "
%s
\n", HTML_PRE_STYLE, comment.c_str());
          }
          else
          {
            fprintf(f, "

Don't be sucker! Describe your function in source code.

", HTML_PRE_STYLE);
          }

          //
          // Horizontal line before next function.
          //

          fprintf(f, "
");
        }
      }
    }
  }

  //
  // Error handler.
  //

  exitCode = 0;

  fail:

  if (exitCode)
  {
    Error("ERROR: Cannot generate html documentation.\n");
  }

  return exitCode;
}

//
// Generate HTML table of content for given component.
// Used to generate menu on the left side, where are
// links to components and functions inside components.
//
// It may generate list of links eg:
//
// * LibFile
//   * FileLoad
//   * FileSave
//   * ...
//
//
// f  - C stream, where to print generated HTML (eg. stdout) (IN).
// si - Source info struct describing given component (IN).
//
// RETURNS: 0 if OK.
//

int GenerateHtmlTableOfContent(FILE *f, SourceInfo *si, int privateMode)
{
  DBG_ENTER("GenerateHtmlTableOfContent");

  int exitCode = -1;

  vector<SourceFile> sourceFiles;

  const char *title = si -> get("TITLE");

  //
  // Collect source files inside project.
  //

  FAIL(CollectSourceFiles(sourceFiles, si, privateMode));

  //
  // Generate table of content.
  //

  fprintf(f, "

", title);

  for (int i = 0; i < sourceFiles.size(); i++)
  {
    const char *fname = sourceFiles[i].name_.c_str();

    vector<FunctionInfo> &fi = sourceFiles[i].functions_;

    fprintf(f, "
%s
\n", title, fname, fname);

    fprintf(f, "
");

    for (int j = 0; j < fi.size(); j++)
    {
      fprintf(f, "
%s
\n", title, fi[j].name_.c_str(), i, fi[j].name_.c_str());
    }

    fprintf(f, "
");
  }

  fprintf(f, "

");

  //
  // Error handler.
  //

  exitCode = 0;

  fail:

  DBG_LEAVE("GenerateHtmlTableOfContent");

  return exitCode;
}

//
// Generate documentation for whole project and put it to 'doc' directory.
//
// privateMode - show internal data too if set to 1 (IN).
//
// RETURNS: 0 if OK.
//

int AutoDocGenerate(int privateMode)
{
  int exitCode = -1;

  SourceInfo proj;

  vector<SourceInfo> comps;

  map<string, vector<SourceInfo> > compsInSubdir;

  map<string, vector<SourceInfo> >::iterator it;

  char currentDir[MAX_PATH] = {0};

  FILE *f    = NULL;
  FILE *ftoc = NULL;

  const char *docRootPath        = NULL;
  const char *docTocHtmlPath     = NULL;
  const char *docContentHtmlPath = NULL;
  const char *docIndexHtmlPath   = NULL;

  int skipExamples = 0;

  //
  // Save current directory.
  //

  FileGetDir(currentDir, sizeof(currentDir));

  //
  // Load all components from tree.
  //

  FAIL(ListComponents(&proj, comps));

  //
  // Assume directories depending on private/public mode.
  //

  if (privateMode)
  {
    docRootPath        = "doc/private";
    docTocHtmlPath     = "doc/private/toc.html";
    docContentHtmlPath = "doc/private/content.html";
    docIndexHtmlPath   = "doc/private/index.html";
  }
  else
  {
    docRootPath        = "doc/public";
    docTocHtmlPath     = "doc/public/toc.html";
    docContentHtmlPath = "doc/public/content.html";
    docIndexHtmlPath   = "doc/public/index.html";
  }

  //
  // Remove private components in public mode.
  //

  skipExamples = proj.getInt("AUTODOC_SKIP_EXAMPLES");

  if (privateMode == 0)
  {
    for (vector<SourceInfo>::iterator it = comps.begin(); it != comps.end(); )
    {
      if ((it -> getInt("AUTODOC_PRIVATE") == 1)
              || proj.doesMatchPrivateDir(&(*it))
                  || (skipExamples && stristr(it -> get("TITLE"), "example")))
      {
        printf("Skipped private component '%s'.\n", it -> get("TITLE"));

        it = comps.erase(it);
      }
      else
      {
        it ++;
      }
    }
  }

  //
  // Create 'doc' subdirectory if not exists.
  // We will store all docuimentation here.
  //

  #ifdef WIN32
  mkdir("doc");
  mkdir(docRootPath);
  #else
  mkdir("doc", S_IRWXU | S_IRGRP | S_IXGRP);
  mkdir(docRootPath, S_IRWXU | S_IRGRP | S_IXGRP);
  #endif

  //
  // Table of content on left frame.
  //

  f = fopen(docTocHtmlPath, "wt+");

  FAILEX(f == NULL, "ERROR: Cannot create 'doc/toc.html' file.\n");

  fprintf(f, "\n");

  //
  // Javascript code to open/close toc subfolders.
  //

  fprintf
  (
    f,
    "\n"
  );

  //
  // Project title.
  //

  fprintf(f, "
%s Project
\n", proj.get("TITLE"));

  //
  // Main components first.
  //

  fprintf(f, "
I. Overview
\n");
  fprintf(f, "
II. Diagram
\n");
  fprintf(f, "
III. Specifications
\n");

  fprintf(f, "
Main components:
\n");

  fprintf(f, "
\n");

  for (int i = 0; i < comps.size(); i++)
  {
    if (strstr(comps[i].get("TITLE"), "example") == NULL)
    {
      FileSetDir(currentDir);

      FileSetDir(comps[i].get("COMP_DIR"));

      fprintf
      (
        f,
        "
"
        "
"
          "[+]"
          "%s"
        "
\n",
        comps[i].get("TITLE"),
        comps[i].get("TITLE"),
        comps[i].get("TITLE"),
        comps[i].get("TITLE")
      );

      GenerateHtmlTableOfContent(f, &comps[i], privateMode);
    }
  }

  fprintf(f, "
");

  //
  // Examples after.
  //

  fprintf(f, "
\n");
  fprintf(f, "
Examples:
\n");

  for (int i = 0; i < comps.size(); i++)
  {
    if (strstr(comps[i].get("TITLE"), "example"))
    {
      FileSetDir(currentDir);

      FileSetDir(comps[i].get("COMP_DIR"));

      fprintf(f, "

%s
\n",
                  comps[i].get("TITLE"), comps[i].get("TITLE"));

      GenerateHtmlTableOfContent(f, &comps[i], privateMode);
    }
  }

  fprintf(f, "
");
  fprintf(f, "");

  FileSetDir(currentDir);

  fclose(f);

  //
  // Dump content.
  //

  f = fopen(docContentHtmlPath, "wt+");

  FAILEX(f == NULL, "ERROR: Cannot create 'doc/content.html' file.\n");

  fprintf(f, "");

  fprintf(f, "
"
             " DO NOT EDIT! This file was generated automatically"
             " by 'qcbuild --makedoc' tool.\n
");

  fprintf(f, "
%s project - technical documentation
\n", proj.get("TITLE"));

  //
  // Table of content on TOP.
  //

  fprintf(f, "
Table of content:
");

  fprintf(f, "
");
    fprintf(f, "
I. Overview
");
    fprintf(f, "
II. Components diagram
");
    fprintf(f, "
III. Components specification
");
  fprintf(f, "
");

  //
  // Segregate components in order to most top subdir e.g.
  // Lib, Client, Server etc.
  //

  for (int i = 0; i < comps.size(); i++)
  {
    compsInSubdir[comps[i].get("TOP_SUBDIR")].push_back(comps[i]);
  }

  if (compsInSubdir.size() == 1)
  {
    DBG_MSG("All sources are inside single directory. Going one level deeper...");

    //
    // All modules are inside single directory.
    // Go one level down.
    //

    compsInSubdir.clear();

    for (int i = 0; i < comps.size(); i++)
    {
      string subTop = FilePathGetDirAtDeep(comps[i].get("COMP_DIR"), 1);

      compsInSubdir[subTop].push_back(comps[i]);
    }
  }

  //
  // I. List of components.
  // Print list of components grouped by most top subdir,
  // but exclude example comopnents.
  //

  fprintf(f, "");
  fprintf(f, "
I. Overview:
");
  fprintf(f, "
");

  for (it = compsInSubdir.begin(); it != compsInSubdir.end(); it ++)
  {
    vector<SourceInfo> &comps = it -> second;

    fprintf(f, "
");

    fprintf(f, "%s
\n", it -> first.c_str());

    for (int i = 0; i < comps.size(); i++)
    {
      if (strstr(comps[i].get("TITLE"), "example") == NULL)
      {
        fprintf(f, "%s
\n",
                    comps[i].get("TITLE"), comps[i].get("TITLE"));
      }
    }

    fprintf(f, "
");
  }

  fprintf(f, "
\n");

  //
  // Print list of examples grouped by most top subdir,
  //

  fprintf(f, "
");
  fprintf(f, "
Examples:
");

  for (it = compsInSubdir.begin(); it != compsInSubdir.end(); it ++)
  {
    vector<SourceInfo> &comps = it -> second;

    fprintf(f, "
");

    fprintf(f, "%s
\n", it -> first.c_str());

    for (int i = 0; i < comps.size(); i++)
    {
      if (strstr(comps[i].get("TITLE"), "example"))
      {
        fprintf(f, "%s
\n",
                    comps[i].get("TITLE"), comps[i].get("TITLE"));
      }
    }

    fprintf(f, "
");
  }

  fprintf(f, "
\n");

  //
  // II. Components diagram.
  //

  fprintf(f, "");
  fprintf(f, "
II. Components diagram:
");

  FAIL(CreateComponentDiagram(f, comps));

  //
  // III. Generate descriptions for every component.
  //

  fprintf(f, "");
  fprintf(f, "
III. Components specifications:
");

  //
  // Dump components specifications.
  //

  for (int i = 0; i < comps.size(); i++)
  {
    printf("Processing '%s'...\n", comps[i].get("TITLE"));

    //
    // Dump component.
    //

    FileSetDir(currentDir);

    FileSetDir(comps[i].get("COMP_DIR"));

    fprintf(f, "", comps[i].get("TITLE"));
    fprintf(f, "
%s component
", comps[i].get("TITLE"));

    GenerateHtmlFromSourceInfo(f, &comps[i], privateMode);
  }

  //
  // End content.
  //

  fprintf(f, "");

  fclose(f);

  //
  // Restore project's root.
  //

  FileSetDir(currentDir);

  //
  // Main index.html including two frames:
  //
  // - toc.html on left
  // - content.html on right
  //

  f = fopen(docIndexHtmlPath, "wt+");

  FAILEX(f == NULL, "ERROR: Cannot create 'doc/index.html' file.\n");

  fprintf
  (
    f,
    ""
      ""
        "<meta http-equiv='content-type' content='text/html; charset=iso-8859-1'>"
      ""
      "<frameset cols='30%%, *'>"
        "<frame src='toc.html' name='toc'>"
        "<frame src='content.html' name='content'>"
      "</frameset>"
    ""
  );

  //
  // Error handler.
  //

  exitCode = 0;

  fail:

  return exitCode;
}

branch_name: refs/heads/main

extension: cpp


text:
// Package ast provides TTCN-3 syntax tree nodes and functions for tree
// traversal.
package ast

import (
	"github.com/nokia/ntt/internal/loc"
	"github.com/nokia/ntt/internal/ttcn3/token"
)

// All node types implement the Node interface.
type Node interface {
	Pos() loc.Pos
	End() loc.Pos
	LastTok() *Token
}

// All expression nodes implement the Expr interface.
type Expr interface {
	Node
	exprNode()
}

// All statement nodes implement the Stmt interface.
type Stmt interface {
	Node
	stmtNode()
}

// All declaration nodes implement the Decl interface.
type Decl interface {
	Node
	declNode()
}

type ErrorNode struct {
	From, To Token
}

func (x ErrorNode) Pos() loc.Pos    { return x.From.Pos() }
func (x ErrorNode) End() loc.Pos    { return x.To.End() }
func (x ErrorNode) LastTok() *Token { return x.To.LastTok() }
func (x ErrorNode) exprNode()       {}
func (x ErrorNode) stmtNode()       {}
func (x ErrorNode) declNode()       {}
func (x ErrorNode) typeSpecNode()   {}

// token functionality shared by Token and Trivia
type Terminal struct {
	pos  loc.Pos
	Kind token.Kind // Token kind like TESTCASE, SEMICOLON, COMMENT, ...
	Lit  string     // Token values for non-operator tokens
}

func (x Terminal) Pos() loc.Pos { return x.pos }
func (x Terminal) End() loc.Pos {
	return loc.Pos(int(x.pos) + len(x.String()))
}

func (x *Terminal) String() string {
	if x.Kind.IsLiteral() {
		return x.Lit
	}
	return x.Kind.String()
}

func (t *Terminal) IsValid() bool {
	return t.pos.IsValid()
}

// A Token represents a TTCN-3 token and implements the Node interface. Tokens are leave-nodes.
type Token struct {
	Terminal
	LeadingTriv  []Trivia
	TrailingTriv []Trivia
}

func NewToken(pos loc.Pos, kind token.Kind, val string) Token {
	return Token{Terminal{pos, kind, val}, nil, nil}
}

// Comments concatenates all leading comments into one single string.
func (t *Token) Comments() string {
	return joinComments(t.LeadingTriv)
}

func (t *Token) LastTok() *Token { return t }

// Trivia represent the parts of the source text that are largely insignificant
// for normal understanding of the code, such as whitespace, comments, and
// preprocessor directives.
type Trivia struct {
	Terminal
}

func NewTrivia(pos loc.Pos, kind token.Kind, val string) Trivia {
	return Trivia{Terminal{pos, kind, val}}
}

type (
	// Ident represents an identifier.
	Ident struct {
		Tok  Token // first identifier token
		Tok2 Token // optional second identifier token, e.g. for "any port"
	}

	// ParametrizedIdent represents a paremetrized identifier, e.g. "f<charstring>".
	ParametrizedIdent struct {
		Ident  *Ident     // Identifier
		Params *ParenExpr // Parameter list
	}

	// A ValueLiteral represents simple literals, like integers, charstrings, ...
	ValueLiteral struct {
		Tok Token
	}

	// A CompositeLiteral represents composite literals, e.g. "{x:=23, y:=5}".
	CompositeLiteral struct {
		LBrace Token  // Position of "{"
		List   []Expr // Expression list
		RBrace Token  // Position of "{"
	}

	// A UnaryExpr represents a unary expresions.
	UnaryExpr struct {
		Op Token // Operator token, like "+", "-", "!", ...
		X  Expr
	}

	// A BinaryExpr represents a binary expression.
	// Possible operands are all tokens with a precedence value, TO and FROM.
	BinaryExpr struct {
		X  Expr  // First operand
		Op Token // Operator token
		Y  Expr  // Second operand
	}

	// A ParenExpr represents parenthized expression lists.
	ParenExpr struct {
		LParen Token  // Position of "(", "<"
		List   []Expr // Expression list
		RParen Token  // Position of ")", ">"
	}

	// A SelectorExpr represents an expression followed by a selector.
	SelectorExpr struct {
		X   Expr  // Preceding expression (might be nil)
		Dot Token // Position of "."
		Sel Expr  // Literal, identifier or reference.
	}

	// A IndexExpr represents an expression followed by an index.
	IndexExpr struct {
		X      Expr  // Preceding expression (might be nil)
		LBrack Token // Position of "["
		Index  Expr  // Actuall index expression (might be "-")
		RBrack Token // Position of "]"
	}

	// A CallExpr represents a regular function call.
	CallExpr struct {
		Fun  Expr       // Function expression
		Args *ParenExpr // Function arguments
	}

	// A LengthExpr represents a length expression.
	LengthExpr struct {
		X    Expr       // Preceding expression
		Len  Token      // Position of "length" keyword
		Size *ParenExpr // Size expression
	}

	// A RedirectExpr represents various redirect expressions
	RedirectExpr struct {
		X             Expr   // Preceding redirected expression
		Tok           Token  // Position of "->"
		ValueTok      Token  // Position of "value" or nil
		Value         []Expr // Value expression
		ParamTok      Token  // Position of "param" or nil
		Param         []Expr // Param expression
		SenderTok     Token  // Position of "sender" or nil
		Sender        Expr   // Sender expression
		IndexTok      Token  // Position of "@index" or nil
		IndexValueTok Token  // Position of "value" or nil
		Index         Expr   // Index expression
		TimestampTok  Token  // Position of "timestamp" or nil
		Timestamp     Expr   // Timestamp expression
	}

	// A ValueExpr represents the return value used by signature based communication.
	ValueExpr struct {
		X   Expr  // Preceding template expression
		Tok Token // Position of "value"
		Y   Expr  // Value expression
	}

	// A ParamExpr represents parametrized map and unmap statements.
	ParamExpr struct {
		X   Expr  // map or unmap statement
		Tok Token // Position "param"
		Y   Expr  // Additional arguments for map/unmap
	}

	// A FromExpr represents a "from" expression, like "any from a".
	FromExpr struct {
		Kind    Token // ANY or ALL
		FromTok Token // Position of "from"
		X       Expr  // Expression
	}

	// A ModifiesExpr represents a "modifies" expression.
	ModifiesExpr struct {
		Tok    Token // Position of "modifies"
		X      Expr  // Base template expression
		Assign Token // Position of ":="
		Y      Expr  // Modifying expression
	}

	// A RegexExpr represents a "regexp" expression.
	RegexpExpr struct {
		Tok    Token // Position of "regexp"
		NoCase Token // Position of "@nocase" or nil
		X      Expr  // Regex expression
	}

	// A PatternExpr represents a "pattern" expression.
	PatternExpr struct {
		Tok    Token // Position of "pattern"
		NoCase Token // Position of "@nocase" of nil
		X      Expr  // Pattern expression
	}

	// A DecmatchExpr represents a "decmatch" expression.
	DecmatchExpr struct {
		Tok    Token // Position of "decmatch"
		Params Expr  // Parameter list or nil
		X      Expr  // Template expression
	}

	// A DecodedExpr represents a "@decoded" expression.
	DecodedExpr struct {
		Tok    Token // Position of "decoded"
		Params Expr  // Parameter list or nil
		X      Expr  // Template expression
	}

	// A DefKindExpr represents a definition kind expression, used by imports
	// and with-attributes.
	DefKindExpr struct {
		Kind Token  // Definition kind, "type", "group", ...
		List []Expr // List of identifiers or except-expressions
	}

	// A ExceptExpr is used by DefKindExpr to express exlusion of specific
	// defintions.
	ExceptExpr struct {
		X         Expr   // (Qualified) identifier or "all"
		ExceptTok Token  // Position of "except"
		LBrace    Token  // Position of "{" or nil
		List      []Expr // List of identifiers or DefKindExprs to exclude
		RBrace    Token  // Position of "}" or nil
	}
)

func (x *Ident) String() string {
	if x.Tok2.IsValid() {
		return x.Tok.String() + " " + x.Tok2.String()
	}
	return x.Tok.String()
}

func (x *Ident) LastTok() *Token {
	if x.Tok2.LastTok().IsValid() {
		return x.Tok2.LastTok()
	}
	return x.Tok.LastTok()
}

func (x *ParametrizedIdent) LastTok() *Token { return x.Params.LastTok() }
func (x *ValueLiteral) LastTok() *Token      { return x.Tok.LastTok() }
func (x *CompositeLiteral) LastTok() *Token  { return x.RBrace.LastTok() }
func (x *UnaryExpr) LastTok() *Token         { return x.X.LastTok() }
func (x *BinaryExpr) LastTok() *Token        { return x.Y.LastTok() }
func (x *ParenExpr) LastTok() *Token         { return x.RParen.LastTok() }
func (x *SelectorExpr) LastTok() *Token      { return x.Sel.LastTok() }
func (x *IndexExpr) LastTok() *Token         { return x.RBrack.LastTok() }
func (x *CallExpr) LastTok() *Token          { return x.Args.LastTok() }
func (x *LengthExpr) LastTok() *Token        { return x.Size.LastTok() }
func (x *RedirectExpr) LastTok() *Token {
	if x.Timestamp != nil {
		return x.Timestamp.LastTok()
	}
	if x.Index != nil {
		return x.Index.LastTok()
	}
	if x.Sender != nil {
		return x.Sender.LastTok()
	}
	if x.Param != nil {
		return x.Param[len(x.Param)-1].LastTok()
	}
	if x.Value != nil {
		return x.Value[len(x.Value)-1].LastTok()
	}
	return x.Tok.LastTok()
}

func (x *ValueExpr) LastTok() *Token    { return x.Y.LastTok() }
func (x *ParamExpr) LastTok() *Token    { return x.Y.LastTok() }
func (x *FromExpr) LastTok() *Token     { return x.X.LastTok() }
func (x *ModifiesExpr) LastTok() *Token { return x.Y.LastTok() }
func (x *RegexpExpr) LastTok() *Token   { return x.X.LastTok() }
func (x *PatternExpr) LastTok() *Token  { return x.X.LastTok() }
func (x *DecmatchExpr) LastTok() *Token { return x.X.LastTok() }
func (x *DecodedExpr) LastTok() *Token  { return x.X.LastTok() }

func (x *DefKindExpr) LastTok() *Token {
	return x.List[len(x.List)-1].LastTok()
}

func (x *ExceptExpr) LastTok() *Token {
	if x.RBrace.LastTok().IsValid() {
		return x.RBrace.LastTok()
	}
	return x.List[len(x.List)-1].LastTok()
}

func (x *Ident) Pos() loc.Pos             { return x.Tok.Pos() }
func (x *ParametrizedIdent) Pos() loc.Pos { return x.Ident.Pos() }
func (x *ValueLiteral) Pos() loc.Pos      { return x.Tok.Pos() }
func (x *CompositeLiteral) Pos() loc.Pos  { return x.LBrace.Pos() }
func (x *UnaryExpr) Pos() loc.Pos         { return x.Op.Pos() }
func (x *BinaryExpr) Pos() loc.Pos        { return x.X.Pos() }
func (x *ParenExpr) Pos() loc.Pos         { return x.LParen.Pos() }
func (x *SelectorExpr) Pos() loc.Pos      { return x.X.Pos() }
func (x *IndexExpr) Pos() loc.Pos         { return x.X.Pos() }
func (x *CallExpr) Pos() loc.Pos          { return x.Fun.Pos() }
func (x *LengthExpr) Pos() loc.Pos        { return x.X.Pos() }
func (x *RedirectExpr) Pos() loc.Pos      { return x.X.Pos() }
func (x *ValueExpr) Pos() loc.Pos         { return x.X.Pos() }
func (x *ParamExpr) Pos() loc.Pos         { return x.X.Pos() }
func (x *FromExpr) Pos() loc.Pos          { return x.Kind.Pos() }
func (x *ModifiesExpr) Pos() loc.Pos      { return x.Tok.Pos() }
func (x *RegexpExpr) Pos() loc.Pos        { return x.Tok.Pos() }
func (x *PatternExpr) Pos() loc.Pos       { return x.Tok.Pos() }
func (x *DecmatchExpr) Pos() loc.Pos      { return x.Tok.Pos() }
func (x *DecodedExpr) Pos() loc.Pos       { return x.Tok.Pos() }
func (x *DefKindExpr) Pos() loc.Pos       { return x.Kind.Pos() }
func (x *ExceptExpr) Pos() loc.Pos        { return x.X.Pos() }

func (x *Ident) End() loc.Pos             { return x.LastTok().End() }
func (x *ParametrizedIdent) End() loc.Pos { return x.LastTok().End() }
func (x *ValueLiteral) End() loc.Pos      { return x.LastTok().End() }
func (x *CompositeLiteral) End() loc.Pos  { return x.LastTok().End() }
func (x *UnaryExpr) End() loc.Pos         { return x.LastTok().End() }
func (x *BinaryExpr) End() loc.Pos        { return x.LastTok().End() }
func (x *ParenExpr) End() loc.Pos         { return x.LastTok().End() }
func (x *SelectorExpr) End() loc.Pos      { return x.LastTok().End() }
func (x *IndexExpr) End() loc.Pos         { return x.LastTok().End() }
func (x *CallExpr) End() loc.Pos          { return x.LastTok().End() }
func (x *LengthExpr) End() loc.Pos        { return x.LastTok().End() }
func (x *RedirectExpr) End() loc.Pos      { return x.LastTok().End() }
func (x *ValueExpr) End() loc.Pos         { return x.LastTok().End() }
func (x *ParamExpr) End() loc.Pos         { return x.LastTok().End() }
func (x *FromExpr) End() loc.Pos          { return x.LastTok().End() }
func (x *ModifiesExpr) End() loc.Pos      { return x.LastTok().End() }
func (x *RegexpExpr) End() loc.Pos        { return x.LastTok().End() }
func (x *PatternExpr) End() loc.Pos       { return x.LastTok().End() }
func (x *DecmatchExpr) End() loc.Pos      { return x.LastTok().End() }
func (x *DecodedExpr) End() loc.Pos       { return x.LastTok().End() }
func (x *DefKindExpr) End() loc.Pos       { return x.LastTok().End() }
func (x *ExceptExpr) End() loc.Pos        { return x.LastTok().End() }

func (x *Ident) exprNode()             {}
func (x *ParametrizedIdent) exprNode() {}
func (x *ValueLiteral) exprNode()      {}
func (x *CompositeLiteral) exprNode()  {}
func (x *UnaryExpr) exprNode()         {}
func (x *BinaryExpr) exprNode()        {}
func (x *ParenExpr) exprNode()         {}
func (x *SelectorExpr) exprNode()      {}
func (x *IndexExpr) exprNode()         {}
func (x *CallExpr) exprNode()          {}
func (x *LengthExpr) exprNode()        {}
func (x *RedirectExpr) exprNode()      {}
func (x *ValueExpr) exprNode()         {}
func (x *ParamExpr) exprNode()         {}
func (x *FromExpr) exprNode()          {}
func (x *ModifiesExpr) exprNode()      {}
func (x *RegexpExpr) exprNode()        {}
func (x *PatternExpr) exprNode()       {}
func (x *DecmatchExpr) exprNode()      {}
func (x *DecodedExpr) exprNode()       {}
func (x *DefKindExpr) exprNode()       {}
func (x *ExceptExpr) exprNode()        {}

type (
	// A BlockStmt represents a curly braces enclosed list of statements.
	BlockStmt struct {
		LBrace Token  // Position of "{"
		Stmts  []Stmt // List of statements
		RBrace Token  // Position of "}"
	}

	// A DeclStmt represents a value declaration used as statement, lika a
	// local variable declaration.
	DeclStmt struct {
		Decl Decl
	}

	// An ExprStmt represents a expression used as statement, like an
	// assignment or function call.
	ExprStmt struct {
		Expr Expr
	}

	// A BranchStmt represents a branch statement.
	BranchStmt struct {
		Tok   Token // REPEAT, BREAK, CONTINUE, LABEL, GOTO
		Label Token // Label literal or nil
	}

	// A ReturnStmt represents a return statement.
	ReturnStmt struct {
		Tok    Token // Position of "return"
		Result Expr  // Resulting expression of nil
	}

	// A AltStmt represents an alternative statement.
	AltStmt struct {
		Tok  Token      // ALT or INTERLEAVE
		Body *BlockStmt // Block statement with alternations
	}

	// A CallStmt represents a "call" statement with communication-block.
	CallStmt struct {
		Stmt Stmt       // "call" statement
		Body *BlockStmt // Block statement with alternations
	}

	// A ForStmt represents a "for" statement.
	ForStmt struct {
		Tok      Token      // Position of "for"
		LParen   Token      // Position of "("
		Init     Stmt       // Initialization statement
		InitSemi Token      // Position of ";"
		Cond     Expr       // Conditional expression
		CondSemi Token      // Position of ";"
		Post     Stmt       // Post iteration statement
		RParen   Token      // Position of ")"
		Body     *BlockStmt // Loop-Body
	}

	// A WhilStmt represents a "while" statement.
	WhileStmt struct {
		Tok  Token      // Position of "while"
		Cond *ParenExpr // Conditional expression
		Body *BlockStmt // Loop-body
	}

	// A DoWhileStmt represents a do-while statement.
	DoWhileStmt struct {
		DoTok    Token      // Position of "do"
		Body     *BlockStmt // Loop-Body
		WhileTok Token      // Position of "while"
		Cond     *ParenExpr // Conditional expression
	}

	// A IfStmt represents a conditional statement.
	IfStmt struct {
		Tok     Token      // Position of "if"
		Cond    Expr       // Conditional expression
		Then    *BlockStmt // True branch
		ElseTok Token      // Position of "else" or nil
		Else    Stmt       // Else branch
	}

	// A SelectStmt represents a select statements.
	SelectStmt struct {
		Tok    Token         // Position of "select"
		Union  Token         // Position of "union" or nil
		Tag    *ParenExpr    // Tag expression
		LBrace Token         // Position of "{"
		Body   []*CaseClause // List of case clauses
		RBrace Token         // Position of "}"
	}

	// A CaseClause represents a case clause.
	CaseClause struct {
		Tok  Token      // Position of "case"
		Case *ParenExpr // nil means else-case
		Body *BlockStmt // Case body
	}

	// A CommClause represents communication clauses used by alt, interleave or check.
	CommClause struct {
		LBrack Token      // Position of '['
		X      Expr       // Conditional guard expression or nil
		Else   Token      // Else-clause of nil
		RBrack Token      // Position of ']'
		Comm   Stmt       // Communication statement
		Body   *BlockStmt // Body of nil
	}
)

func (x *BlockStmt) LastTok() *Token { return x.RBrace.LastTok() }
func (x *DeclStmt) LastTok() *Token  { return x.Decl.LastTok() }
func (x *ExprStmt) LastTok() *Token  { return x.Expr.LastTok() }

func (x *BranchStmt) LastTok() *Token {
	if x.Label.LastTok().IsValid() {
		return x.Label.LastTok()
	}
	return x.Tok.LastTok()
}

func (x *ReturnStmt) LastTok() *Token {
	if x.Result != nil {
		return x.Result.LastTok()
	}
	return x.Tok.LastTok()
}

func (x *CallStmt) LastTok() *Token    { return x.Body.LastTok() }
func (x *AltStmt) LastTok() *Token     { return x.Body.LastTok() }
func (x *ForStmt) LastTok() *Token     { return x.Body.LastTok() }
func (x *WhileStmt) LastTok() *Token   { return x.Body.LastTok() }
func (x *DoWhileStmt) LastTok() *Token { return x.Cond.LastTok() }

func (x *IfStmt) LastTok() *Token {
	if x.Else != nil {
		return x.Else.LastTok()
	}
	return x.Then.LastTok()
}

func (x *SelectStmt) LastTok() *Token { return x.RBrace.LastTok() }
func (x *CaseClause) LastTok() *Token { return x.Body.LastTok() }

func (x *CommClause) LastTok() *Token {
	if x.Body != nil {
		return x.Body.LastTok()
	}
	return x.Comm.LastTok()
}

func (x *BlockStmt) Pos() loc.Pos   { return x.LBrace.Pos() }
func (x *DeclStmt) Pos() loc.Pos    { return x.Decl.Pos() }
func (x *ExprStmt) Pos() loc.Pos    { return x.Expr.Pos() }
func (x *BranchStmt) Pos() loc.Pos  { return x.Tok.Pos() }
func (x *ReturnStmt) Pos() loc.Pos  { return x.Tok.Pos() }
func (x *CallStmt) Pos() loc.Pos    { return x.Stmt.Pos() }
func (x *AltStmt) Pos() loc.Pos     { return x.Tok.Pos() }
func (x *ForStmt) Pos() loc.Pos     { return x.Tok.Pos() }
func (x *WhileStmt) Pos() loc.Pos   { return x.Tok.Pos() }
func (x *DoWhileStmt) Pos() loc.Pos { return x.DoTok.Pos() }
func (x *IfStmt) Pos() loc.Pos      { return x.Tok.Pos() }
func (x *SelectStmt) Pos() loc.Pos  { return x.Tok.Pos() }
func (x *CaseClause) Pos() loc.Pos  { return x.Tok.Pos() }
func (x *CommClause) Pos() loc.Pos  { return x.LBrack.Pos() }

func (x *BlockStmt) End() loc.Pos   { return x.LastTok().End() }
func (x *DeclStmt) End() loc.Pos    { return x.LastTok().End() }
func (x *ExprStmt) End() loc.Pos    { return x.LastTok().End() }
func (x *BranchStmt) End() loc.Pos  { return x.LastTok().End() }
func (x *ReturnStmt) End() loc.Pos  { return x.LastTok().End() }
func (x *CallStmt) End() loc.Pos    { return x.LastTok().End() }
func (x *AltStmt) End() loc.Pos     { return x.LastTok().End() }
func (x *ForStmt) End() loc.Pos     { return x.LastTok().End() }
func (x *WhileStmt) End() loc.Pos   { return x.LastTok().End() }
func (x *DoWhileStmt) End() loc.Pos { return x.LastTok().End() }
func (x *IfStmt) End() loc.Pos      { return x.LastTok().End() }
func (x *SelectStmt) End() loc.Pos  { return x.LastTok().End() }
func (x *CaseClause) End() loc.Pos  { return x.LastTok().End() }
func (x *CommClause) End() loc.Pos  { return x.LastTok().End() }

func (x *BlockStmt) stmtNode()   {}
func (x *DeclStmt) stmtNode()    {}
func (x *ExprStmt) stmtNode()    {}
func (x *BranchStmt) stmtNode()  {}
func (x *ReturnStmt) stmtNode()  {}
func (x *CallStmt) stmtNode()    {}
func (x *AltStmt) stmtNode()     {}
func (x *ForStmt) stmtNode()     {}
func (x *WhileStmt) stmtNode()   {}
func (x *DoWhileStmt) stmtNode() {}
func (x *IfStmt) stmtNode()      {}
func (x *SelectStmt) stmtNode()  {}
func (x *CaseClause) stmtNode()  {}
func (x *CommClause) stmtNode()  {}

// All nested types implement TypeSpec interface.
type TypeSpec interface {
	Node
	typeSpecNode()
}

type (
	// A Field represents a named struct member or sub type definition
	Field struct {
		DefaultTok       Token    // Position of "@default" or nil
		Type             TypeSpec // Type
		Name             Expr     // Name
		TypePars         *FormalPars
		ValueConstraint  *ParenExpr  // Value constraint or nil
		LengthConstraint *LengthExpr // Length constraint or nil
		Optional         Token       // Position of "optional" or nil
	}

	// A RefSpec represents a type reference.
	RefSpec struct {
		X Expr
	}

	// A StructSpec represents a struct type specification.
	StructSpec struct {
		Kind   Token    // RECORD, SET, UNION
		LBrace Token    // Position of "{"
		Fields []*Field // Member list
		RBrace Token    // Position of "}"
	}

	// A ListSpec represents a list type specification.
	ListSpec struct {
		Kind     Token       // RECORD, SET
		Length   *LengthExpr // Length constraint or nil
		OfTok    Token       // Position of "of"
		ElemType TypeSpec    // Element type specification
	}

	// A EnumSpec represents a enumeration type specification.
	EnumSpec struct {
		Tok    Token  // Position of "enumerated"
		LBrace Token  // Position of "{"
		Enums  []Expr // Enum list
		RBrace Token  // Position of "}"
	}

	// A BehaviourSpec represents a behaviour type specification.
	BehaviourSpec struct {
		Kind   Token       // TESTCASE, FUNCTION, ALTSTEP
		Params *FormalPars // Parameter list or nil
		RunsOn *RunsOnSpec // runs on spec or nil
		System *SystemSpec // system spec or nil
		Return *ReturnSpec // return value spec or nil
	}
)

func (x *Field) LastTok() *Token {
	if x.Optional.LastTok().IsValid() {
		return x.Optional.LastTok()
	}
	if x.LengthConstraint != nil {
		return x.LengthConstraint.LastTok()
	}
	if x.ValueConstraint != nil {
		return x.ValueConstraint.LastTok()
	}
	return x.Name.LastTok()
}

func (x *RefSpec) LastTok() *Token    { return x.X.LastTok() }
func (x *StructSpec) LastTok() *Token { return x.RBrace.LastTok() }
func (x *ListSpec) LastTok() *Token   { return x.ElemType.LastTok() }
func (x *EnumSpec) LastTok() *Token   { return x.RBrace.LastTok() }

func (x *BehaviourSpec) LastTok() *Token {
	if x.Return != nil {
		return x.Return.LastTok()
	}
	if x.System != nil {
		return x.System.LastTok()
	}
	if x.RunsOn != nil {
		return x.RunsOn.LastTok()
	}
	if x.Params != nil {
		return x.Params.LastTok()
	}
	return x.Kind.LastTok()
}

func (x *Field) Pos() loc.Pos {
	if x.DefaultTok.Pos().IsValid() {
		return x.DefaultTok.Pos()
	}
	return x.Type.Pos()
}

func (x *RefSpec) Pos() loc.Pos       { return x.X.Pos() }
func (x *StructSpec) Pos() loc.Pos    { return x.Kind.Pos() }
func (x *ListSpec) Pos() loc.Pos      { return x.Kind.Pos() }
func (x *EnumSpec) Pos() loc.Pos      { return x.Tok.Pos() }
func (x *BehaviourSpec) Pos() loc.Pos { return x.Kind.Pos() }

func (x *Field) End() loc.Pos         { return x.LastTok().End() }
func (x *RefSpec) End() loc.Pos       { return x.LastTok().End() }
func (x *StructSpec) End() loc.Pos    { return x.LastTok().End() }
func (x *ListSpec) End() loc.Pos      { return x.LastTok().End() }
func (x *EnumSpec) End() loc.Pos      { return x.LastTok().End() }
func (x *BehaviourSpec) End() loc.Pos { return x.LastTok().End() }

func (x *Field) typeSpecNode()         {}
func (x *RefSpec) typeSpecNode()       {}
func (x *StructSpec) typeSpecNode()    {}
func (x *ListSpec) typeSpecNode()      {}
func (x *EnumSpec) typeSpecNode()      {}
func (x *BehaviourSpec) typeSpecNode() {}

type (
	// A ValueDecl represents a value declaration.
	ValueDecl struct {
		Kind                Token // VAR, CONST, TIMER, PORT, TEMPLATE, MODULEPAR
		TemplateRestriction *RestrictionSpec
		Modif               Token // "@lazy", "@fuzzy" or nil
		Type                Expr
		Decls               []Expr
		With                *WithSpec
	}

	TemplateDecl struct {
		RestrictionSpec
		Modif       Token // "@lazy", "@fuzzy" or nil
		Type        Expr
		Name        *Ident
		TypePars    *FormalPars
		Params      *FormalPars
		ModifiesTok Token
		Base        Expr
		AssignTok   Token
		Value       Expr
		With        *WithSpec
	}

	// A ModuleParameterGroup represents a deprecated module parameter list
	ModuleParameterGroup struct {
		Tok    Token        // Position of "modulepar"
		LBrace Token        // Position of "{"
		Decls  []*ValueDecl // Module parameter list
		RBrace Token        // Position of "}"
		With   *WithSpec
	}

	// A FuncDecl represents a behaviour definition.
	FuncDecl struct {
		External Token // Position of "external" or nil
		Kind     Token // TESTCASE, ALTSTEP, FUNCTION
		Name     *Ident
		Modif    Token // Position of "@deterministic" or nil
		TypePars *FormalPars
		Params   *FormalPars // Formal parameter list or nil
		RunsOn   *RunsOnSpec // Optional runs-on-spec
		Mtc      *MtcSpec    // Optional mtc-spec
		System   *SystemSpec // Optional system-spec
		Return   *ReturnSpec // Optional return-spec
		Body     *BlockStmt  // Body or nil
		With     *WithSpec
	}

	// A SignatureDecl represents a signature type for procedure based communication.
	SignatureDecl struct {
		Tok          Token // Position of "signature"
		Name         *Ident
		TypePars     *FormalPars
		Params       *FormalPars
		NoBlock      Token       // Optional "noblock"
		Return       *ReturnSpec // Optional return-spec
		ExceptionTok Token       // Position of "exeception" or nil
		Exception    *ParenExpr  // Exception list
		With         *WithSpec
	}

	// A SubTypeDecl represents a named sub type declaration
	SubTypeDecl struct {
		TypeTok Token  // Position of "type"
		Field   *Field // Field spec
		With    *WithSpec
	}

	// A StructTypeDecl represents a name struct type.
	StructTypeDecl struct {
		TypeTok  Token // Position of "type"
		Kind     Token // RECORD, SET, UNION
		Name     Expr  // Name
		TypePars *FormalPars
		LBrace   Token    // Position of "{"
		Fields   []*Field // Member list
		RBrace   Token    // Position of }"
		With     *WithSpec
	}

	// A EnumTypeDecl represents a named enum type.
	EnumTypeDecl struct {
		TypeTok  Token // Position of "type"
		EnumTok  Token // Position of "ENUMERATED"
		Name     Expr
		TypePars *FormalPars
		LBrace   Token  // Position of "{"
		Enums    []Expr // Enum list
		RBrace   Token  // Position of "}"
		With     *WithSpec
	}

	// A BehaviourTypeDecl represents a named behaviour type.
	BehaviourTypeDecl struct {
		TypeTok  Token // Position of "type"
		Kind     Token // TESTCASE, ALTSTEP, FUNCTION
		Name     Expr
		TypePars *FormalPars
		Params   *FormalPars // Formal parameter list
		RunsOn   *RunsOnSpec // Optional runs-on spec
		System   *SystemSpec // Optional system spec
		Return   *ReturnSpec // Optional return spec
		With     *WithSpec
	}

	PortTypeDecl struct {
		TypeTok  Token
		PortTok  Token
		Name     Expr
		TypePars *FormalPars
		Kind     Token // MIXED, MESSAGE, PROCEDURE
		Realtime Token
		LBrace   Token
		Attrs    []Node
		RBrace   Token
		With     *WithSpec
	}

	PortAttribute struct {
		Kind  Token // IN, OUT, INOUT, ADDRESS
		Types []Expr
	}

	PortMapAttribute struct {
		MapTok   Token // MAP, UNMAP
		ParamTok Token
		Params   *FormalPars
	}

	ComponentTypeDecl struct {
		TypeTok    Token
		CompTok    Token
		Name       Expr
		TypePars   *FormalPars
		ExtendsTok Token
		Extends    []Expr
		Body       *BlockStmt
		With       *WithSpec
	}
)

func (x *FuncDecl) IsTest() bool {
	return x.Kind.Kind == token.TESTCASE
}

func (x *ValueDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.Decls[len(x.Decls)-1].LastTok()
}

func (x *TemplateDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.Value.LastTok()
}

func (x *ModuleParameterGroup) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.RBrace.LastTok()
}

func (x *FuncDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	if x.Body != nil {
		return x.Body.LastTok()
	}
	if x.Return != nil {
		return x.Return.LastTok()
	}
	if x.Params != nil {
		return x.Params.LastTok()
	}
	return x.Kind.LastTok()
}

func (x *SignatureDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	if x.Exception != nil {
		return x.Exception.LastTok()
	}
	if x.Return != nil {
		return x.Return.LastTok()
	}
	if x.NoBlock.LastTok().IsValid() {
		return x.NoBlock.LastTok()
	}
	if x.Params != nil {
		return x.Params.LastTok()
	}
	return x.Name.LastTok()
}

func (x *SubTypeDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.Field.LastTok()
}

func (x *StructTypeDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.RBrace.LastTok()
}

func (x *EnumTypeDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.RBrace.LastTok()
}

func (x *BehaviourTypeDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	if x.Return != nil {
		return x.Return.LastTok()
	}
	if x.System != nil {
		return x.System.LastTok()
	}
	if x.RunsOn != nil {
		return x.RunsOn.LastTok()
	}
	if x.Params != nil {
		return x.Params.LastTok()
	}
	return x.Name.LastTok()
}

func (x *PortTypeDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.RBrace.LastTok()
}

func (x *PortAttribute) LastTok() *Token {
	return x.Types[len(x.Types)-1].LastTok()
}

func (x *PortMapAttribute) LastTok() *Token {
	return x.Params.LastTok()
}

func (x *ComponentTypeDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.Body.LastTok()
}

func (x *ValueDecl) Pos() loc.Pos {
	if x.Kind.Pos().IsValid() {
		return x.Kind.Pos()
	}
	return x.Type.Pos()
}

func (x *ModuleParameterGroup) Pos() loc.Pos {
	return x.Tok.Pos()
}

func (x *FuncDecl) Pos() loc.Pos {
	if x.External.Kind == token.EXTERNAL {
		return x.External.Pos()
	}
	return x.Kind.Pos()
}

func (x *SignatureDecl) Pos() loc.Pos     { return x.Tok.Pos() }
func (x *SubTypeDecl) Pos() loc.Pos       { return x.TypeTok.Pos() }
func (x *StructTypeDecl) Pos() loc.Pos    { return x.TypeTok.Pos() }
func (x *EnumTypeDecl) Pos() loc.Pos      { return x.TypeTok.Pos() }
func (x *BehaviourTypeDecl) Pos() loc.Pos { return x.TypeTok.Pos() }
func (x *PortTypeDecl) Pos() loc.Pos      { return x.TypeTok.Pos() }
func (x *PortAttribute) Pos() loc.Pos     { return x.Kind.Pos() }
func (x *PortMapAttribute) Pos() loc.Pos  { return x.MapTok.Pos() }
func (x *ComponentTypeDecl) Pos() loc.Pos { return x.TypeTok.Pos() }

func (x *ValueDecl) End() loc.Pos            { return x.LastTok().End() }
func (x *TemplateDecl) End() loc.Pos         { return x.LastTok().End() }
func (x *ModuleParameterGroup) End() loc.Pos { return x.LastTok().End() }
func (x *FuncDecl) End() loc.Pos             { return x.LastTok().End() }
func (x *SignatureDecl) End() loc.Pos        { return x.LastTok().End() }
func (x *SubTypeDecl) End() loc.Pos          { return x.LastTok().End() }
func (x *StructTypeDecl) End() loc.Pos       { return x.LastTok().End() }
func (x *EnumTypeDecl) End() loc.Pos         { return x.LastTok().End() }
func (x *BehaviourTypeDecl) End() loc.Pos    { return x.LastTok().End() }
func (x *PortTypeDecl) End() loc.Pos         { return x.LastTok().End() }
func (x *PortAttribute) End() loc.Pos        { return x.LastTok().End() }
func (x *PortMapAttribute) End() loc.Pos     { return x.LastTok().End() }
func (x *ComponentTypeDecl) End() loc.Pos    { return x.LastTok().End() }

func (x *ValueDecl) declNode()            {}
func (x *TemplateDecl) declNode()         {}
func (x *ModuleParameterGroup) declNode() {}
func (x *FuncDecl) declNode()             {}
func (x *SignatureDecl) declNode()        {}
func (x *SubTypeDecl) declNode()          {}
func (x *StructTypeDecl) declNode()       {}
func (x *EnumTypeDecl) declNode()         {}
func (x *BehaviourTypeDecl) declNode()    {}
func (x *PortTypeDecl) declNode()         {}
func (x *PortAttribute) declNode()        {}
func (x *PortMapAttribute) declNode()     {}
func (x *ComponentTypeDecl) declNode()    {}

// ------------------------------------------------------------------------
// Modules and Module Definitions

type (
	Module struct {
		Tok      Token
		Name     *Ident
		Language *LanguageSpec
		LBrace   Token
		Defs     []*ModuleDef
		RBrace   Token
		With     *WithSpec
	}

	ModuleDef struct {
		Visibility Token
		Def        Node
	}

	ControlPart struct {
		Tok  Token
		Body *BlockStmt
		With *WithSpec
	}

	ImportDecl struct {
		ImportTok Token
		FromTok   Token
		Module    *Ident
		Language  *LanguageSpec
		LBrace    Token
		List      []*DefKindExpr
		RBrace    Token
		With      *WithSpec
	}

	GroupDecl struct {
		Tok    Token
		Name   *Ident
		LBrace Token
		Defs   []*ModuleDef
		RBrace Token
		With   *WithSpec
	}

	FriendDecl struct {
		FriendTok Token
		ModuleTok Token
		Module    *Ident
		With      *WithSpec
	}
)

func (x *Module) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	if x.RBrace.IsValid() {
		return x.RBrace.LastTok()
	}
	if l := len(x.Defs); l > 0 {
		return x.Defs[l-1].LastTok()
	}
	if x.Language != nil {
		return x.Language.LastTok()
	}

	if x.Name != nil {
		return x.Name.LastTok()
	}

	return x.Tok.LastTok()
}

func (x *ModuleDef) LastTok() *Token {
	return x.Def.LastTok()
}

func (x *ControlPart) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.Body.LastTok()
}

func (x *ImportDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.RBrace.LastTok()
}

func (x *GroupDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.RBrace.LastTok()
}

func (x *FriendDecl) LastTok() *Token {
	if x.With != nil {
		return x.With.LastTok()
	}
	return x.Module.LastTok()
}

func (x *Module) Pos() loc.Pos { return x.Tok.Pos() }

func (x *ModuleDef) Pos() loc.Pos {
	if x.Visibility.Pos().IsValid() {
		return x.Visibility.Pos()
	}
	return x.Def.Pos()
}

func (x *ControlPart) Pos() loc.Pos { return x.Tok.Pos() }
func (x *ImportDecl) Pos() loc.Pos  { return x.ImportTok.Pos() }
func (x *GroupDecl) Pos() loc.Pos   { return x.Tok.Pos() }
func (x *FriendDecl) Pos() loc.Pos  { return x.FriendTok.Pos() }

func (x *Module) End() loc.Pos      { return x.LastTok().End() }
func (x *ModuleDef) End() loc.Pos   { return x.LastTok().End() }
func (x *ControlPart) End() loc.Pos { return x.LastTok().End() }
func (x *ImportDecl) End() loc.Pos  { return x.LastTok().End() }
func (x *GroupDecl) End() loc.Pos   { return x.LastTok().End() }
func (x *FriendDecl) End() loc.Pos  { return x.LastTok().End() }

// ------------------------------------------------------------------------
// Miscellaneous

type (
	LanguageSpec struct {
		Tok  Token
		List []Token
	}

	RestrictionSpec struct {
		TemplateTok Token
		LParen      Token
		Tok         Token
		RParen      Token
	}

	RunsOnSpec struct {
		RunsTok Token
		OnTok   Token
		Comp    Expr
	}

	SystemSpec struct {
		Tok  Token
		Comp Expr
	}

	MtcSpec struct {
		Tok  Token
		Comp Expr
	}

	ReturnSpec struct {
		Tok         Token
		Restriction *RestrictionSpec
		Modif       Token
		Type        Expr
	}

	FormalPars struct {
		LParen Token
		List   []*FormalPar
		RParen Token
	}

	FormalPar struct {
		Direction           Token
		TemplateRestriction *RestrictionSpec
		Modif               Token
		Type                Expr
		Name                Expr
	}

	WithSpec struct {
		Tok    Token
		LBrace Token
		List   []*WithStmt
		RBrace Token
	}

	WithStmt struct {
		Kind     Token
		Override Token
		LParen   Token
		List     []Node
		RParen   Token
		Value    Expr
	}
)

func (x *LanguageSpec) LastTok() *Token { return x.List[len(x.List)-1].LastTok() }
func (x *RestrictionSpec) LastTok() *Token {
	if x.RParen.LastTok().IsValid() {
		return x.RParen.LastTok()
	}
	return x.Tok.LastTok()
}
func (x *RunsOnSpec) LastTok() *Token { return x.Comp.LastTok() }
func (x *SystemSpec) LastTok() *Token { return x.Comp.LastTok() }
func (x *MtcSpec) LastTok() *Token    { return x.Comp.LastTok() }
func (x *ReturnSpec) LastTok() *Token { return x.Type.LastTok() }
func (x *FormalPars) LastTok() *Token { return x.RParen.LastTok() }
func (x *FormalPar) LastTok() *Token  { return x.Name.LastTok() }
func (x *WithSpec) LastTok() *Token   { return x.RBrace.LastTok() }
func (x *WithStmt) LastTok() *Token   { return x.Value.LastTok() }

func (x *LanguageSpec) Pos() loc.Pos { return x.Tok.Pos() }
func (x *RestrictionSpec) Pos() loc.Pos {
	if x.TemplateTok.Pos().IsValid() {
		return x.TemplateTok.Pos()
	}
	return x.Tok.Pos()
}
func (x *RunsOnSpec) Pos() loc.Pos { return x.RunsTok.Pos() }
func (x *SystemSpec) Pos() loc.Pos { return x.Tok.Pos() }
func (x *MtcSpec) Pos() loc.Pos    { return x.Tok.Pos() }
func (x *ReturnSpec) Pos() loc.Pos { return x.Tok.Pos() }
func (x *FormalPars) Pos() loc.Pos { return x.LParen.Pos() }

func (x *FormalPar) Pos() loc.Pos {
	if x.Direction.Pos().IsValid() {
		return x.Direction.Pos()
	}
	if x.TemplateRestriction.Pos().IsValid() {
		return x.TemplateRestriction.Pos()
	}
	if x.Modif.Pos().IsValid() {
		return x.Modif.Pos()
	}
	return x.Type.Pos()
}

func (x *WithSpec) Pos() loc.Pos        { return x.LastTok().End() }
func (x *WithStmt) Pos() loc.Pos        { return x.LastTok().End() }
func (x *LanguageSpec) End() loc.Pos    { return x.LastTok().End() }
func (x *RestrictionSpec) End() loc.Pos { return x.LastTok().End() }
func (x *RunsOnSpec) End() loc.Pos      { return x.LastTok().End() }
func (x *SystemSpec) End() loc.Pos      { return x.LastTok().End() }
func (x *MtcSpec) End() loc.Pos         { return x.LastTok().End() }
func (x *ReturnSpec) End() loc.Pos      { return x.LastTok().End() }
func (x *FormalPars) End() loc.Pos      { return x.LastTok().End() }
func (x *FormalPar) End() loc.Pos       { return x.LastTok().End() }
func (x *WithSpec) End() loc.Pos        { return x.LastTok().End() }
func (x *WithStmt) End() loc.Pos        { return x.LastTok().End() }


text:
SUMMARY = "Netfilter connection tracking timeout library"
DESCRIPTION = "Userspace library providing a programming interface (API) to the Linux kernel netfilter fine-grain connection tracking timeout infrastructure"
SECTION = "libs"
LICENSE = "GPLv2+"
LIC_FILES_CHKSUM = "file://COPYING;md5=8ca43cbc842c2336e835926c2166c28b"
DEPENDS = "libmnl"

SRC_URI = "http://www.netfilter.org/projects/libnetfilter_cttimeout/files/libnetfilter_cttimeout-${PV}.tar.bz2;name=tar \
           file://libnetfilter-cttimeout-visibility-hidden.patch \
"
SRC_URI[tar.md5sum] = "7697437fc9ebb6f6b83df56a633db7f9"
SRC_URI[tar.sha256sum] = "aeab12754f557cba3ce2950a2029963d817490df7edb49880008b34d7ff8feba"

S = "${WORKDIR}/libnetfilter_cttimeout-${PV}"

inherit autotools pkgconfig

repository: ni/meta-openembedded

repo_name: ni/meta-openembedded

branch_name: refs/heads/nilrt/master/hardknott

gha_language: BitBake


text:
file(REMOVE_RECURSE
  "CMakeFiles/ttcp_blocking.dir/ttcp_blocking.cc.o"
  "CMakeFiles/ttcp_blocking.dir/common.cc.o"
  "CMakeFiles/ttcp_blocking.dir/main.cc.o"
  "../../../bin/ttcp_blocking.pdb"
  "../../../bin/ttcp_blocking"
)

# Per-language clean rules from dependency scanning.
foreach(lang CXX)
  include(CMakeFiles/ttcp_blocking.dir/cmake_clean_${lang}.cmake OPTIONAL)
endforeach()

gha_license_id: NOASSERTION

extension: cmake


text:
package network

import (
	"cjs/atourofgo/shared/application"
	"context"
	"fmt"
	"net"
	"sync/atomic"
)

type Server struct {
	listener  net.Listener
	conns     map[int32]*ServerConn
	ctx       context.Context
	ctxCancel context.CancelFunc
	app       *application.Application
}

func NewServer(app *application.Application) *Server {
	return &Server{
		conns: make(map[int32]*ServerConn),
		app:   app,
	}
}

func (s *Server) Run(addr Address, handler func(*ServerConn, []byte, int)) bool {
	listener, e := net.Listen("tcp", addr.ToString())
	if e != nil {
		fmt.Printf("listen error. err[%s]\n", e.Error())
		return false
	}

	s.listener = listener

	fmt.Printf("new server listening on [%d]\n", addr.Port)

	s.app.Wg.Add(1)
	go func() {
		defer s.app.Wg.Done()

		s.ctx, s.ctxCancel = context.WithCancel(s.app.Ctx)
		var sid int32 = 0

	AcceptLoop:
		for {
			select {
			case <-s.ctx.Done():
				break AcceptLoop
			default:
			}

			conn, e := s.listener.Accept()
			if e != nil {
				fmt.Printf("accept error. err[%s]\n", e.Error())
				break AcceptLoop
			}

			fmt.Printf("new conn established\n")

			c := NewServerConn(s.app, s, conn)
			s.conns[atomic.AddInt32(&sid, 1)] = c

			c.Handler(handler)
		}

		fmt.Println("end of listener goroutine")
	}()

	return true
}

func (s *Server) Stop() {
	s.listener.Close()
	for _, c := range s.conns {
		c.Stop()
	}
}

func (s *Server) GetFirstConn() *ServerConn {
	for _, v := range s.conns {
		return v
	}
	return nil
}

func (s *Server) GetConn(idx int32) *ServerConn {
	return s.conns[idx]
}

// todo: round robin connection getter 만들기

gha_language: Python


text:
/***********************************************************
  TLE から ISS の位置・速度を計算
  : 但し、座標系は BLH(Beta(Latitude), Lambda(Longitude), Height)
  : 指定 UT1 からの TEME 座標計算は iss_sgp4_teme

    DATE        AUTHOR       VERSION
    2021.05.27  mk-mode.com  1.00 新規作成

  Copyright(C) 2021 mk-mode.com All Rights Reserved.
  ---
  引数 : JST（日本標準時）
           書式：最大23桁の数字
                 （先頭から、西暦年(4), 月(2), 日(2), 時(2), 分(2), 秒(2),
                             1秒未満(9)（小数点以下9桁（ナノ秒）まで））
                 無指定なら現在(システム日時)と判断。
  ---
  MEMO:
    TEME: True Equator, Mean Equinox; 真赤道面平均春分点
     PEF: Pseudo Earth Fixed; 擬地球固定座標系
    ECEF: Earth Centered, Earth Fixed; 地球中心・地球固定直交座標系
***********************************************************/
#include "blh.hpp"
#include "eop.hpp"
#include "sgp4.hpp"
#include "time.hpp"
#include "tle.hpp"

#include <cstdlib>   // for EXIT_XXXX
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

int main(int argc, char* argv[]) {
  namespace ns = iss_sgp4_blh;
  std::string tm_str;            // time string
  unsigned int s_tm;             // size of time string
  int s_nsec;                    // size of nsec string
  int ret;                       // return of functions
  struct tm t = {};              // for work
  struct timespec jst;           // JST
  struct timespec utc;           // UTC
  struct timespec ut1;           // UT1
  struct timespec tai;           // TAI
  double pm_x;                   // 極運動(x)
  double pm_y;                   // 極運動(y)
  std::string lod_str;           // LOD 文字列
  double lod;                    // LOD
  std::vector<std::string> tle;  // TLE
  ns::Satellite sat;             // 衛星情報
  ns::PvTeme    teme;            // 位置・速度(TEME)
  ns::PvBlh     blh;             // 位置・速度(BLH)

  try {
    // 現在日時(UT1) 取得
    if (argc > 1) {
      // コマンドライン引数より取得
      tm_str = argv[1];
      s_tm = tm_str.size();
      if (s_tm > 23) {
        std::cout << "[ERROR] Over 23-digits!" << std::endl;
        return EXIT_FAILURE;
      }
      s_nsec = s_tm - 14;
      std::istringstream is(tm_str);
      is >> std::get_time(&t, "%Y%m%d%H%M%S");
      jst.tv_sec  = mktime(&t);
      jst.tv_nsec = 0;
      if (s_tm > 14) {
        jst.tv_nsec = std::stod(
            tm_str.substr(14, s_nsec) + std::string(9 - s_nsec, '0'));
      }
    } else {
      // 現在日時の取得
      ret = std::timespec_get(&jst, TIME_UTC);
      if (ret != 1) {
        std::cout << "[ERROR] Could not get now time!" << std::endl;
        return EXIT_FAILURE;
      }
    }

    // EOP データ取得
    utc = ns::jst2utc(jst);
    ns::Eop o_e(utc);
    pm_x = o_e.pm_x;
    pm_y = o_e.pm_y;
    lod  = o_e.lod;
    ut1  = ns::utc2ut1(utc);
    tai  = ns::utc2tai(utc);
    std::cout << ns::gen_time_str(jst) << " JST" << std::endl;
    std::cout << ns::gen_time_str(utc) << " UTC" << std::endl;
    std::cout << ns::gen_time_str(ut1) << " UT1" << std::endl;
    std::cout << ns::gen_time_str(tai) << " TAI" << std::endl;

    // TLE 読み込み, gravconst 取得
    ns::Tle o_t(ut1);
    tle = o_t.get_tle();

    // ISS 初期位置・速度の取得
    ns::Sgp4 o_s(ut1, tle);
    sat = o_s.twoline2rv();

    // 指定 UT1 の ISS 位置・速度の取得
    teme = o_s.propagate(sat);

    // TEME -> BLH 変換
    ns::Blh o_b(ut1, tai, pm_x, pm_y, lod);
    blh = o_b.teme2blh(teme);

    // 結果出力
    std::cout << "---" << std::endl;
    std::cout << std::fixed << std::setprecision(8);
    std::cout << "EOP: " << o_e.eop << std::endl;
    std::cout << "---" << std::endl;
    std::cout << "TLE: " << tle[0] << std::endl;
    std::cout << "     " << tle[1] << std::endl;
    std::cout << "---" << std::endl;
    std::cout << std::fixed << std::setprecision(8);
    std::cout << "TEME: POS = ["
              << std::setw(16) << teme.r.x << ", "
              << std::setw(16) << teme.r.y << ", "
              << std::setw(16) << teme.r.z
              << "]" << std::endl;
    std::cout << "      VEL = ["
              << std::setw(16) << teme.v.x << ", "
              << std::setw(16) << teme.v.y << ", "
              << std::setw(16) << teme.v.z
              << "]" << std::endl;
    std::cout << "---" << std::endl;
    std::cout << std::fixed << std::setprecision(4);
    std::cout << "WGS84(BLH):" << std::endl
              << "     BETA(Latitude) = " << std::setw(9) << blh.r.b
              << " °" << std::endl
              << "  LAMBDA(Longitude) = " << std::setw(9) << blh.r.l
              << " °" << std::endl
              << "             HEIGHT = " << std::setw(9) << blh.r.h / 1000.0
              << " km" << std::endl
              << "           VELOCITY = " << std::setw(9) << blh.v
              << " km/s" << std::endl;
  } catch (...) {
      std::cerr << "EXCEPTION!" << std::endl;
      return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}


text:
#======================================#
#           SUMMARY/LICENCE            #
#--------------------------------------#
SUMMARY = "Flex (The Fast Lexical Analyzer)"
HOMEPAGE = "http://sourceforge.net/projects/flex/"

LICENSE = "BSD"
LIC_FILES_CHKSUM = "file://COPYING;md5=e4742cf92e89040b39486a6219b68067"

#======================================#
#           REQUIRE/INHERIT            #
#--------------------------------------#
inherit autotools gettext texinfo

#======================================#
#                SOURCE                #
#--------------------------------------#
SRC_URI = "${SOURCEFORGE_MIRROR}/flex/flex-${PV}.tar.bz2;name=source                \
           file://do_not_create_pdf_doc.patch                                       \
           file://0001-tests-add-a-target-for-building-tests-without-runnin.patch   \
           file://0002-avoid-c-comments-in-c-code-fails-with-gcc-6.patch            \
           file://CVE-2016-6354.patch                                               \
           file://disable-tests.patch                                               \
           "

SRC_URI[source.md5sum] = "266270f13c48ed043d95648075084d59"
SRC_URI[source.sha256sum] = "24e611ef5a4703a191012f80c1027dc9d12555183ce0ecd46f3636e587e9b8e9"

#======================================#
#           DEPENDS/PROVIDES           #
#--------------------------------------#
RDEPENDS_${PN}_append = " m4 "

#======================================#
#         BUILD CONFIGURATIONS         #
#--------------------------------------#
M4 = "${bindir}/m4"
M4_class-native = "${STAGING_BINDIR_NATIVE}/m4"

EXTRA_OECONF = " ac_cv_path_M4=${M4} "
EXTRA_OEMAKE = " m4=${STAGING_BINDIR_NATIVE}/m4 "

#======================================#
#                TASKS                 #
#--------------------------------------#

#======================================#
#            PACKAGES/FILES            #
#--------------------------------------#

#======================================#
#            INSTALL SCRIPT            #
#--------------------------------------#

#======================================#
#             ALTERNATIVES             #
#--------------------------------------#

#======================================#
#           USERADD/SYSTEMD            #
#--------------------------------------#

#======================================#
#                 TEST                 #
#--------------------------------------#


text:
package gcp_exporter

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/PuerkitoBio/rehttp"
	"github.com/go-kit/log"
	"github.com/grafana/dskit/multierror"
	"github.com/prometheus-community/stackdriver_exporter/collectors"
	"github.com/prometheus-community/stackdriver_exporter/utils"
	"github.com/prometheus/client_golang/prometheus"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/monitoring/v3"
	"google.golang.org/api/option"
	"gopkg.in/yaml.v2"

	"github.com/grafana/agent/pkg/integrations"
	integrations_v2 "github.com/grafana/agent/pkg/integrations/v2"
	"github.com/grafana/agent/pkg/integrations/v2/metricsutils"
)

func init() {
	integrations.RegisterIntegration(&Config{})
	integrations_v2.RegisterLegacy(&Config{}, integrations_v2.TypeMultiplex, metricsutils.NewNamedShim("gcp"))
}

type Config struct {
	ProjectIDs            []string      `yaml:"project_ids"`
	MetricPrefixes        []string      `yaml:"metrics_prefixes"`
	ExtraFilters          []string      `yaml:"extra_filters"`
	RequestInterval       time.Duration `yaml:"request_interval"`
	RequestOffset         time.Duration `yaml:"request_offset"`
	IngestDelay           bool          `yaml:"ingest_delay"`
	DropDelegatedProjects bool          `yaml:"drop_delegated_projects"`
	ClientTimeout         time.Duration `yaml:"gcp_client_timeout"`
}

var DefaultConfig = Config{
	ClientTimeout:         15 * time.Second,
	RequestInterval:       5 * time.Minute,
	RequestOffset:         0,
	IngestDelay:           false,
	DropDelegatedProjects: false,
}

// UnmarshalYAML implements yaml.Unmarshaler for Config
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
	*c = DefaultConfig

	type plain Config
	return unmarshal((*plain)(c))
}

func (c *Config) Name() string {
	return "gcp_exporter"
}

func (c *Config) InstanceKey(_ string) (string, error) {
	// We use a hash of the config so our key is unique when leveraged with v2
	// The config itself doesn't have anything which can uniquely identify it.
	bytes, err := yaml.Marshal(c)
	if err != nil {
		return "", err
	}
	hash := md5.Sum(bytes)
	return hex.EncodeToString(hash[:]), nil
}

func (c *Config) NewIntegration(l log.Logger) (integrations.Integration, error) {
	if err := c.Validate(); err != nil {
		return nil, err
	}

	svc, err := createMonitoringService(context.Background(), c.ClientTimeout)
	if err != nil {
		return nil, err
	}

	var gcpCollectors []prometheus.Collector
	for _, projectID := range c.ProjectIDs {
		monitoringCollector, err := collectors.NewMonitoringCollector(
			projectID,
			svc,
			collectors.MonitoringCollectorOptions{
				MetricTypePrefixes:    c.MetricPrefixes,
				ExtraFilters:          parseMetricExtraFilters(c.ExtraFilters),
				RequestInterval:       c.RequestInterval,
				RequestOffset:         c.RequestOffset,
				IngestDelay:           c.IngestDelay,
				DropDelegatedProjects: c.DropDelegatedProjects,

				// If FillMissingLabels ensures all metrics with the same name have the same label set. It's not often
				// that GCP metrics have different labels but if it happens the prom registry will panic.
				FillMissingLabels: true,

				// If AggregateDeltas is disabled the data produced is not useful at all. See https://github.com/prometheus-community/stackdriver_exporter#what-to-know-about-aggregating-delta-metrics
				// for more info
				AggregateDeltas: true,
			},
			l,
			collectors.NewInMemoryDeltaCounterStore(l, 30*time.Minute),
			collectors.NewInMemoryDeltaDistributionStore(l, 30*time.Minute),
		)
		if err != nil {
			return nil, fmt.Errorf("failed to create monitoring collector: %w", err)
		}
		gcpCollectors = append(gcpCollectors, monitoringCollector)
	}

	return integrations.NewCollectorIntegration(
		c.Name(), integrations.WithCollectors(gcpCollectors...),
	), nil
}

func (c *Config) Validate() error {
	configErrors := multierror.MultiError{}

	if c.ProjectIDs == nil || len(c.ProjectIDs) == 0 {
		configErrors.Add(errors.New("no project_ids defined"))
	}

	if c.MetricPrefixes == nil || len(c.MetricPrefixes) == 0 {
		configErrors.Add(errors.New("at least 1 metrics_prefixes is required"))
	}

	if len(c.ExtraFilters) > 0 {
		filterPrefixToFilter := map[string][]string{}
		for _, filter := range c.ExtraFilters {
			splitFilter := strings.Split(filter, ":")
			if len(splitFilter) <= 1 {
				configErrors.Add(fmt.Errorf("%s is an invalid filter a filter must be of the form <metric_type>:<filter_expression>", filter))
				continue
			}
			filterPrefix := splitFilter[0]
			if _, exists := filterPrefixToFilter[filterPrefix]; !exists {
				filterPrefixToFilter[filterPrefix] = []string{}
			}
			filterPrefixToFilter[filterPrefix] = append(filterPrefixToFilter[filterPrefix], filter)
		}

		for filterPrefix, filters := range filterPrefixToFilter {
			validFilterPrefix := false
			for _, metricPrefix := range c.MetricPrefixes {
				if strings.HasPrefix(metricPrefix, filterPrefix) {
					validFilterPrefix = true
					break
				}
			}
			if !validFilterPrefix {
				configErrors.Add(fmt.Errorf("no metric_prefixes started with %s which means the extra_filters %s will not have any effect", filterPrefix, strings.Join(filters, ",")))
			}
		}
	}

	return configErrors.Err()
}

func createMonitoringService(ctx context.Context, httpTimeout time.Duration) (*monitoring.Service, error) {
	googleClient, err := google.DefaultClient(ctx, monitoring.MonitoringReadScope)
	if err != nil {
		return nil, fmt.Errorf("error creating Google client: %v", err)
	}

	googleClient.Timeout = httpTimeout
	googleClient.Transport = rehttp.NewTransport(
		googleClient.Transport,
		rehttp.RetryAll(
			rehttp.RetryMaxRetries(4),
			rehttp.RetryStatuses(http.StatusServiceUnavailable)),
		rehttp.ExpJitterDelay(time.Second, 5*time.Second),
	)

	monitoringService, err := monitoring.NewService(ctx,
		option.WithHTTPClient(googleClient),
	)
	if err != nil {
		return nil, fmt.Errorf("error creating Google Stackdriver Monitoring service: %v", err)
	}

	return monitoringService, nil
}

func parseMetricExtraFilters(filters []string) []collectors.MetricFilter {
	var extraFilters []collectors.MetricFilter
	for _, ef := range filters {
		efPrefix, efModifier := utils.GetExtraFilterModifiers(ef, ":")
		if efPrefix != "" {
			extraFilter := collectors.MetricFilter{
				Prefix:   efPrefix,
				Modifier: efModifier,
			}
			extraFilters = append(extraFilters, extraFilter)
		}
	}
	return extraFilters
}

repository: grafana/agent

repo_name: grafana/agent